I'm trying to use a column from a navigation property to do a calculation inside a grouped select statment like so:
var result = await (
from items in Items.Include(e=>e.ItemInfo)
where items.status == "INV"
group rolls by items.origin into grp
select new
{
origin = grp.Key.origin,
total = (grp.Sum(e => e.count * (e.ItemInfo.price + e.ItemInfo.upcharge))),
}).ToListAsync();
However, it can't translate this saying
The LINQ expression '(EntityShaperExpression:
EntityType: itemTable
ValueBufferExpression:
(ProjectionBindingExpression: EmptyProjectionMember)
IsNullable: False
).count * (EntityShaperExpression:
EntityType: itemTable
ValueBufferExpression:
(ProjectionBindingExpression: EmptyProjectionMember)
IsNullable: False
).ItemInfo.price' could not be translated.
I've also tried using:
var result= Item.Include(e=>e.ItemInfo)
.Where(e => e.status == "INV")
.GroupBy(e => e.origin)
.Select(g => new {origin = g.Key.origin,
total = (g.Sum(e=> e.count * (e.ItemInfo.price+e.ItemInfo.upcharge)))});
This seems like it should be a simple query. Is there a way around this?
Put navigation property into projection:
var query =
from items in ItemDatabase
where items.status == "INV"
group new { items, items.ItemInfo } by items.origin into grp
select new
{
origin = grp.Key,
total = grp.Sum(e => e.items.count * (e.ItemInfo.price + e.ItemInfo.upcharge)),
};
Related
I'm trying to do the retrieve the last record in each group like it does here
https://stackoverflow.com/a/20770779/4789608
but in Entity Framework Core. Based on what's on the link, I can get the SQL to work to bring back the correct data using
select *
from [Location]
where [LocationModelId] in (select max([LocationModelId])
from [Location]
group by [UserModelId])
or
select m1.*
from [Location] m1
left outer join [Location] m2 on (m1.[LocationModelId]< m2.[LocationModelId]
and m1.[UserModelId] = m2.[UserModelId])
This is the closest I've gotten based on that link
locationDetails = _context.Location
.GroupBy(p => p.UserModelId)
.Select(p => p.FirstOrDefault(w => w.UserModelId == p.Max(m => m.UserModelId)))
.OrderBy(p => p.DateCreated)
.ToList();
which returns this error message so, it's definitely not working.
The LINQ expression 'GroupByShaperExpression:\r\nKeySelector: l.UserModelId, \r\nElementSelector:EntityShaperExpression: \r\n EntityType: LocationModel\r\n ValueBufferExpression: \r\n ProjectionBindingExpression: EmptyProjectionMember\r\n IsNullable: False\r\n\r\n .FirstOrDefault(w => w.UserModelId == GroupByShaperExpression:\r\n KeySelector: l.UserModelId, \r\n ElementSelector:EntityShaperExpression: \r\n EntityType: LocationModel\r\n ValueBufferExpression: \r\n ProjectionBindingExpression: EmptyProjectionMember\r\n IsNullable: False\r\n\r\n .Max(m => m.UserModelId))' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'
This query should get you desired output. It is not fast as just SQL with window functions, but it should be acceptable.
var unique = _context.Location
.Select(x => new {x.UserModelId})
.Distinct();
var query =
from u in unique
from l in _context.Location
.Where(x => x.UserModelId == u.UserModelId)
.OrderByDescending(x.DateCreated)
.Take(1)
select l;
var locationDetails = query.ToList();
I am currently trying to implement a Report for a customer using Entity Framework Core 5 (also tested 6) and came across a problem, that I couldn't resolve.
I am trying to query a List of all customers / bank accounts with their total sales per month.
Therefore I am trying to group all of the customers bookings, that fit the criteria, by their Month and sum up their amounts.
Shouldn't be that hard of a task.
This is my Query:
context.Kontens
.Select(k => new
{
Creditor = context.DebitorKreditors
.Include(k => k.Kontakt)
.FirstOrDefault(d => d.Nr == k.KtoNr),
Sums = k.BuchZeilenKtos
.Where(b => b.Buch.Belegdatum.Year == DateTime.Now.Year
&& (
(b.GegenKto.KtoNr >= xxxxxx && b.GegenKto.KtoNr <= xxxxxx)
|| (b.GegenKto.KtoNr >= xxxxxx && b.GegenKto.KtoNr <= xxxxxx)
|| (b.GegenKto.KtoNr >= xxxxxx && b.GegenKto.KtoNr <= xxxxxx)
)
)
.GroupBy(b => b.Buch.Belegdatum.Month)
.Select(g => new
{
Sum = g.Sum(b => b.Betrag * (b.SollHaben == "-" || b.SollHaben == "H" ? -1 : 1)),
Month = g.Key
}),
Sum334 = k.BuchZeilenKtos
.Where(b => b.GegenKto.KtoNr >= xxxxxx && b.GegenKto.KtoNr <= xxxxxx)
.Sum(b => b.Betrag * (b.SollHaben == "-" || b.SollHaben == "H" ? -1 : 1))
})
.Where(k => k.Creditor.Kreditor && k.Sums.Any())
.OrderBy(k => k.Creditor.Nr)
.ToList()
Translations:
BuchzeilenKtos = Bookings
Kontens = Bank Accounts
DebitorKreditors = Customers
Buch = Booking
The bank account numbers have been removed due to privacy reasons.
With this I am getting the following error complaining about missing key columns:
System.InvalidOperationException: Unable to translate collection subquery in projection since it uses 'Distinct' or 'Group By' operations and doesn't project key columns of all of it's tables which are required to generate results on client side. Missing column: b.ID. Either add column(s) to the projection or rewrite query to not use 'GroupBy'/'Distinct' operation.
I tried numerous things including changing the GroupBy to also include the key columns:
.GroupBy(b => new
{
b.Buch.Belegdatum.Month,
b.Id,
b.GegenKto,
b
})
But this should produce wrong results anyway from what I understand about LINQ Grouping.
Nevertheless, Now EF is complaining about not being able to translate the query and wants me to change to clientside processing, which isn't an option due to the very high amount of bookings being processed:
System.InvalidOperationException: The LINQ expression 'DbSet<BuchZeilen>()
.Where(b => EF.Property<Nullable<Guid>>(EntityShaperExpression:
EntityType: Konten
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
, "Id") != null && object.Equals(
objA: (object)EF.Property<Nullable<Guid>>(EntityShaperExpression:
EntityType: Konten
ValueBufferExpression:
ProjectionBindingExpression: EmptyProjectionMember
IsNullable: False
, "Id"),
objB: (object)EF.Property<Nullable<Guid>>(b, "KtoId")))
.Join(
inner: DbSet<Buchung>(),
outerKeySelector: b => EF.Property<Nullable<Guid>>(b, "BuchId"),
innerKeySelector: b0 => EF.Property<Nullable<Guid>>(b0, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<BuchZeilen, Buchung>(
Outer = o,
Inner = i
))
.LeftJoin(
inner: DbSet<Konten>(),
outerKeySelector: b => EF.Property<Nullable<Guid>>(b.Outer, "GegenKtoId"),
innerKeySelector: k0 => EF.Property<Nullable<Guid>>(k0, "Id"),
resultSelector: (o, i) => new TransparentIdentifier<TransparentIdentifier<BuchZeilen, Buchung>, Konten>(
Outer = o,
Inner = i
))
.Where(b => b.Outer.Inner.Belegdatum.Year == DateTime.Now.Year && b.Inner.KtoNr >= 311000 && b.Inner.KtoNr <= 319999 || b.Inner.KtoNr >= 334000 && b.Inner.KtoNr <= 334999 || b.Inner.KtoNr >= 340000 && b.Inner.KtoNr <= 340999)
.GroupBy(
keySelector: b => new {
Month = b.Outer.Inner.Belegdatum.Month,
Id = b.Outer.Outer.Id,
GegenKto = b.Inner,
b = b.Outer.Outer
},
elementSelector: b => b.Outer.Outer)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
I've read, that EF Core 5 has removed certain functionality on GroupBy/Distinct for correlated sub queries but I am not sure whether that is my exact scenario. In my opinion the query shouldn't be too specific for EF to handle.
Does anybody know how I can achieve, what I am trying to do or whether it is possible at least?
I'm trying to select multiple columns not in a group by using linq - c#.
Using linq, I'm trying to group by ISNULL(fieldOne,''),ISNULL(fieldTo,'') and then select field_One, field_Two, field_Three for each group. So for each row that the group by would return, I want to see numerous rows.
So far I have the following, but can't seem to select all the needed columns.
var xy = tableQueryable.Where(
!string.IsNullOrEmpty(cust.field_One)
|| ! string.IsNullOrEmpty(ust.field_Two)
).GroupBy(cust=> new { field_One= cust.field_One ?? string.Empty, field_Tow = cust.field_Two ?? string.Empty}).Where(g=>g.Count()>1).AsQueryable();
Can somebody help pls?
You are pretty much there - all you are missing is a Select from the group:
var xy = tableQueryable
.Where(!string.IsNullOrEmpty(cust.first_name) || ! string.IsNullOrEmpty(ust.lastName))
.GroupBy(cust=> new { first_name = cust.first_name ?? string.Empty, last_name = cust.last_name ?? string.Empty})
.Where(g=>g.Count()>1)
.ToList() // Try to work around the cross-apply issue
.SelectMany(g => g.Select(cust => new {
Id = cust.Id
, cust.FirstName
, cust.LastName
, cust.RepId
}));
Select from each group does the projection of the fields that you want, while SelectMany dumps all the results into a flat list.
Would this work for you?
var groupsWithDuplicates = tableQueryable
.Where(c => !string.IsNullOrWhiteSpace(c.first_name) || !string.IsNullOrWhiteSpace(c.last_name))
.GroupBy(c => new { FirstName = c.first_name ?? "", LastName = c.last_name ?? "" })
.Where(group => group.Count() > 1) // Only keep groups with more than one item
.ToList();
var duplicates = groupsWithDuplicates
.SelectMany(g => g) // Flatten out groups into a single collection
.Select(c => new { c.first_name, c.last_name, c.customer_rep_id });
For me I have used following query to do the filter Customer and get the customer records group by the JobFunction. In my case the issue get resolved after adding the .AsEnumerable() after the where solve the problem.
var query = _context.Customer
.Where(x => x.JobTitle.ToUpper().Contains(searchText.ToUpper())).AsEnumerable()
.GroupBy(item => item.JobFunction,
(key, group) => new {
JobFunction = key,
CustomerRecords = group.ToList().Select(c => c).ToList()
})
.ToList();
I would like to order a Listview based on the products'name it displays. My website is made of several languages and thus I built a linked table with a product name for each languages.
When I try to sort it I always get this error
DbSortClause expressions must have a type that is order comparable.
Parameter name: key
My code is the following:
IQueryable<Product> query = from p in _dbCtx.Products
where p.LanguageProduct.Any(lg => lg.Language == _currentCulture)
select p;
...
if (keys.Contains("OrderBy"))
{
if (Request.QueryString["OrderBy"] == "NameAsc")
query = query.OrderBy(t => t.LanguageProduct.Select(v => v.ProductName));
}
Any suggestions? Many thanks in advance.
EDIT: Maybe I haven't been clear enough. Therefore, I'll add some more code:
IQueryable<Product> query = from p in _dbCtx.Products
where p.IsVisible == true
where p.LanguageProduct.Any(lg => lg.Language == _currentCulture)
select p;
if (keys.Contains("Indiv"))
{
if (Request.QueryString["Indiv"] == "IndivYes")
query = query.Where(c => c.IsCustomizable == true);
if (Request.QueryString["Indiv"] == "IndivNo")
query = query.Where(c => c.IsCustomizable == false);
}
if (keys.Contains("OrderBy"))
{
if (Request.QueryString["OrderBy"] == "NameAsc")
query = query.OrderBy(t => t.LanguageProduct.Select(v => v.ProductName));
else if (Request.QueryString["OrderBy"] == "NameDes")
query = query.OrderByDescending(t => t.LanguageProduct.Select(v => v.ProductName));
else if (Request.QueryString["OrderBy"] == "PriceAsc")
query = query.OrderBy(t => t.ListPrice);
else if (Request.QueryString["OrderBy"] == "PriceDes")
query = query.OrderByDescending(t => t.ListPrice);
}
Everything works fine by adding successive where clauses to my query until it has to order by name. Hereunder is the structure of my database:
table: Product ProductTranslation
columns: id ReferenceName FKId Language ProductName
Example: 1 FirstProduct 1 fr-FR Produit 1
1 de-DE Produkt 1
1 en-US Product 1
You can do this using this:
var queryable = query.SelectMany(p => p.LanguageProduct, (p, l) => new{p,l})
.OrderBy(t => t.l.ProductName)
.Select(t => t.p);
I would like to "combine" to linq queries into the same gridview. Though I don't think I could use innerjoin on this.
The queries get orders from the database, and I have 2 tables with orders from different places.
In the gridview I want to display all orders from first table and second table.
Like this:
OrderID - Item - Amount etc ---From table 1
OrderID - Item - Amount etc ---From table 2
etc..
My current query for getting orders from the first table are:
var query = from o in db.Orders
join y in db.OrderLines on o.OrderID equals y.OrderID
join x in db.Products on y.ItemNumber equals x.ItemNumber
where o.AccountNumber == AppSession.CurrentLoginTicket.AccountNumber
select new
{
o.OrderID,
o.AxaptaSalesId,
y.ItemNumber,
x.Name,
x.ProductFormatName,
y.Quantity,
y.Price,
Status = dltRep.getOrderStatus(o.OrderID, o.AxaptaSalesId, y.ItemNumber).Substring(0, dltRep.getOrderStatus(o.OrderID, o.AxaptaSalesId, y.ItemNumber).LastIndexOf("|")),
Levering = dltRep.getOrderStatus(o.OrderID, o.AxaptaSalesId, y.ItemNumber).Substring(dltRep.getOrderStatus(o.OrderID, o.AxaptaSalesId, y.ItemNumber).LastIndexOf("|")).Replace("|", "")
};
The other table would have the same information. It's named AxSale.
I hope this is possible and someone could help me out :)
EDIT: new "problem"
I wan't to get the variable createdDate to be the first element x.CreatedDate in either the first linq seq. or the second.
How do I do this?
var created = purchases.OrderByDescending(x => x.CreatedDate).
Select(x => new { x.CreatedDate, x.LineSupplierAccountNO }).
GroupBy(x => x.LineSupplierAccountNO);
if (created.Count() > 1)
{
created = purchases.OrderBy(x => x.CreatedDate).
Select(x => new { x.CreatedDate, x.LineSupplierAccountNO }).
GroupBy(x => x.LineSupplierAccountNO);
}
var createdDate = created.FirstOrDefault();
Solution code:
var created = purchases.OrderBy(x => x.CreatedDate).Select(x => x);
if (created.GroupBy(x => x.LineSupplierAccountNO).Count() > 1)
{
created = purchases.OrderByDescending(x => x.CreatedDate).Select(x => x);
}
var createdDate = created.First().CreatedDate;
Use UNION operator to join results with same fields. Here is example from http://code.msdn.microsoft.com/windowsdesktop/101-LINQ-Samples-3fb9811b
public void Linq49()
{
List<Product> products = GetProductList();
List<Customer> customers = GetCustomerList();
var productFirstChars =
from p in products
select p.ProductName[0];
var customerFirstChars =
from c in customers
select c.CompanyName[0];
var uniqueFirstChars = productFirstChars.Union(customerFirstChars);
Console.WriteLine("Unique first letters from Product names and Customer names:");
foreach (var ch in uniqueFirstChars)
{
Console.WriteLine(ch);
}
}
I believe you are looking for Union
Try this link