I have a database with peoples names and ages amongst other things. I have a query which groups by names and gets amount of each name matching the criteria. The ListHelper type is only a class containing the two properties.
IEnumerable<ListHelper> HelperEnumerable = null
HelperEnumerable = _repository.Persons
.Where(b => b.Age < 18)
.GroupBy(
n => n.FirstName
, a => a.FirstName
, (key, count) => new ListHelper { Name = key, Amount = count.Count() }
);
When I ToList() the HelperEnumerable the result is like:
Name: "Michael", Amount: 100,
Name: "Eva", Amount: 122,
Name: "Lisa", Amount: 71,
etc
How can i get a similar result but with count of all persons matching the criteria with a result like this:
Name: "All", Amount: 17280
I would like to have the key value pair so all the rest of the code could stay the same, only this query would return the count of all matchig rows instead of grouped by any particular columm.
I've tried this which returns only the int count:
HelperEnumerable = _repository.Persons
.Where(b => b.Age < 18).Count();
And I can't add a
.Select(a => (key,count) new ListHelper{ key = "All", count = a })
after a Count() to try to project the result to have two fields.
What does:
IEnumerable<ListHelper> HelperEnumerable = null
HelperEnumerable = _repository.Persons
.Where(b => b.Age < 18)
.GroupBy(
n => "All"
, (key, count) => new ListHelper { Name = key, Amount = count.Count() }
);
Not do that you need it to do?
or why not just:
new ListHelper{ key = "All", count = _repository.Persons.Where(b => b.Age < 18).Count() };
??
Related
I've got a CQLinq query which returns a list of methods and a list of members for each of them. Exporting the query result will only show the number of elements. I thought about using a Linq Aggregate( (a,b) => a + ',' + b). Is there a better solution?
let type = Application.Types.WithFullName("WPF.ViewModels.CouponViewModel").Single()
let dicoFields = type.Fields
.ToDictionary(f => f, f => f.MethodsUsingMe.Where(m => m.ParentType == f.ParentType))
let dicoMethods = type.Methods
.ToDictionary(m => m, m => m.MembersUsed.Where(f => f.ParentType == m.ParentType))
// The partition algorithm on both dicos here
//from pair in dicoFields
//orderby pair.Value.Count() descending
//select new { pair.Key, pair.Value }
from pair in dicoMethods
orderby pair.Value.Count() descending
select new { pair.Key, pair.Value}
Indeed you can rewrite your query this way:
let type = Application.Types.WithFullName("WPF.ViewModels.CouponViewModel").Single()
let dicoMembers = type.ChildMembers
.ToDictionary(x => x, x =>
x.IsField ? x.AsField.MethodsUsingMe.Where(m => m.ParentType == x.ParentType):
x.AsMethod.MembersUsed.Where(f => f.ParentType == x.ParentType))
from pair in dicoMembers
orderby pair.Value.Count() descending
select new {
pair.Key,
str = pair.Value.Any() ?
pair.Value.Select(x => x.Name).Aggregate( (a,b) => a + " ; " + b) :
"empty"
}
Both methods and fields are taken account
Methods using fields and members used by methods are aggregated in a string
Then you can export the result:
I'm trying to combine these 2 Linq queries into 1:
var query = from s in _context.Set<StockInventoryItem>()
where s.StockCatalogueItemId == id
group s by s.StockType into g
select new
{
inStock = g.Sum(x => x.QtyInStock),
};
var query2 = from p in _context.Set<PurchaseOrderItem>()
where p.StockCatalogueItemId == id
group p by p.StockType into g2
select new
{
onOrder = g2.Sum(x => x.QtyStillDue)
};
Note that the filtering, grouping and output is the same from both tables, and I want the results to look like this:
StockType inStock onOrder
+----------+--------+--------+
Type 1 4 3
+----------+--------+--------+
Type 2 0 1
i.e. Quantities grouped by StockType
This is EF code first and there is no direct relationship between these tables, which is why I'm trying this query in the service layer so I can access both entities.
You should be able to "shoehorn" both groups into the same sequence with anonymous types and Concat, and then count the results separately, like this:
var query = _context.Set<StockInventoryItem>()
.Where(ii => ii.StockCatalogueItemId == id)
.Select(ii => new {
II = ii, PO = (PurchaseOrderItem)null
}).Concat(_context.Set<PurchaseOrderItem>()
.Where(po => po.StockCatalogueItemId == id)
.Select(po => new {
II = (StockInventoryItem)null, PO = po
})).GroupBy(p => II != null ? ii.StockType : PO.StockType)
.Select(g => new {
InStock = g.Sum(p => p.II != null ? p.II.QtyInStock : 0)
, OnOrder = g.Sum(p => p.PO != null ? p.PO.QtyStillDue: 0)
});
I'm trying to filter a table using where clause. When I the write the queries separately they work fine:
IQueryable<Movie> movies = db.Movies;
movies = movies.Where(movie =>
movie.MovieToGenres.Any(genreItem => genreItem.Genre_ID == 34)
);
movies = movies.Where(movie =>
movie.MovieToGenres.Any(genreItem => genreItem.Genre_ID == 35)
);
However I have to use it in a foreach loop:
List<int> genre_ids = new List<int>();
genre_ids.Add(34);
genre_ids.Add(35);
IQueryable<Movie> movies = db.Movies;
foreach (var genre_id in genre_ids)
{
movies = movies.Where(movie =>
movie.MovieToGenres.Any(genreItem => genreItem.Genre_ID == genre_id)
);
}
When I do that, on the SQL side the query parameters are #p0 = 35, #p1 = 35 instead of #p0 = 34, #p1 = 35. I don't know why.
It's another case of capturing the loop variable. There's only one genre_id variable which is captured by all the lambda expressions. It's easy to fix by introducing a new variable on each iteration, and capture that instead:
foreach (var genre_id in genre_ids)
{
int genreCopy = genre_id;
movies = movies.Where(movie => movie.MovieToGenres.Any(
genreItem => genreItem.Genre_ID == genreCopy));
}
In C# 5 this may be unnecessary - the behaviour may well be changing.
Probably you are looking something like this
List<int> genres = new List<int>() { 34, 35, 36 };
movies = movies.Where(movie => movie.MovieToGenres.Any(genreItem => genres.Contains(genreItem.Genre_ID));
it should translates to IN ( 34, 35, 36)
I have following query:
var accounts =
from account in context.Accounts
from guranteer in account.Gurantors
select new AccountsReport
{
CreditRegistryId = account.CreditRegistryId,
AccountNumber = account.AccountNo,
DateOpened = account.DateOpened,
};
return accounts.AsEnumerable()
.Select((account, index) => new AccountsReport()
{
RecordNumber = FormattedRowNumber(account, index + 1),
CreditRegistryId = account.CreditRegistryId,
AccountNumber = FormattedAccountNumber(account.AccountType, account.AccountNumber)}).OrderByDescending(c => c.StateChangeDate);
It works fine except one problem and that is it returns records number in reverse order like 3, 2,1 because of .OrderByDescending(c => c.StateChangeDate);
Can I show the record number in ascendeing order while keeping the records in descending order.
Please suggest.
Thanks
Try using OrderBy on RecordNumber and then ThenByDescending on StateChangeDate
.OrderBy(c => c.RecordNumber).ThenByDescending(c => c.StateChangeDate);
I have a list of objects. E.g. List<coin> where they contain a string(denom) and int(year).
If the list contains:
"Quarter", 1954
"Quarter", 1990
"Penny", 1925
"Nickel", 1900
"Nickel", 2000
How can I get a resultant list where it contains the unique values with just the most recent year? E.g.:
"Quarter", 1990
"Penny", 1925
"Nickel", 2000
You can do this by grouping by name, then either ordering and taking the first result, or by using something like MaxBy from MoreLINQ:
var query = coins.GroupBy(x => x.Name)
.Select(g => g.MaxBy(x => x.Year));
or
var query = coins.GroupBy(x => x.Name)
.Select(g => g.OrderByDescending(x => x.Year).First());
You can do this using group by like:
var query = from coin in myList
group coin by coin.Name into grouped
select new
{
Name = grouped.Key
Year = grouped.Max(x => x.Year)
};
For another sample like this, check out "max - grouped" in the 101 Linq examples: http://msdn.microsoft.com/en-us/vcsharp/aa336747#maxGrouped
var coins = new Coin[] { ... };
var recentCoins =
from coin in coins
group coin by coin.Denom into g
select new
{
Denom = g.Key,
MostRecentYear = g.Max(c => c.Year)
};