I have LINQ expression to take top 15 most frequently used answers
Here is expression
var latestAnswers = await _dbContext.TextAnswers.Include(x => x.CompanySurvey).ThenInclude(x => x.Survey)
.Where(x => x.CompanySurvey.Survey.FiscalYear == 2022)
.GroupBy(x => x.Answer)
.OrderByDescending(g => g.Count())
.Take(15)
.ToListAsync();
But I get this error
The LINQ expression 'DbSet() .Include(x => x.CompanySurvey) .ThenInclude(x => x.Survey) .Where(x => x.CompanySurvey.Survey.FiscalYear == (int?)2022) .GroupBy(x => x.Answer) .OrderByDescending(g => g .AsQueryable() .Count()) .Take(__p_0)' 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'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I can't understood why it cant be translated.
How I can fix this?
EF Core 6 has to support such queries, but looks like full implementation support is moved to EF Core 7
After conversation looks like it is not needed to get grouped records from database, but just grouping key and Count
var latestAnswers = await _dbContext.TextAnswers
.Where(x => x.CompanySurvey.Survey.FiscalYear == 2022)
.GroupBy(x => x.Answer)
.Select(g => new { Answer = g.Key, Count = g.Count() })
.OrderByDescending(x => x.Count)
.Take(15)
.ToListAsync();
I rewrite my code like this
var latestAnswersQuery = await _dbContext.TextAnswers
.Include(x => x.CompanySurvey).ThenInclude(x => x.Survey)
.Where(x => x.CompanySurvey.Survey.FiscalYear == 2022)
.ToListAsync();
var latestAnswers = latestAnswersQuery.GroupBy(x => x.Answer).OrderByDescending(g => g.Count()).Take(15);
return latestAnswers;
And now everything great
Related
I Have this code. It works fine but when I have two same maximal values it appear 2 times. So I need to use OrderBy. But I dont know how. Thanks for any help.
IQueryable<PerformanceRealization> pr = _context.PerformanceRealization
.Where(u => u.Deadline == _context.PerformanceRealization
.Where(x => x.GroupRealizationId == u.GroupRealizationId)
.Max(x => x.Deadline)
)
.Select(u => u);
Here is the SQL code with GROUP BY
SELECT PR.GroupRealizationId
FROM Stores.PerformanceRealization PR
LEFT JOIN Stores.GroupRealization ON Stores.GroupRealization.Id = PR.GroupRealizationId
WHERE PR.Deadline = (SELECT MAX(Deadline)
FROM Stores.PerformanceRealization PR2
WHERE PR.GroupRealizationId = PR2.GroupRealizationId)
GROUP BY PR.GroupRealizationId
You can select the first object from the group
IQueryable<PerformanceRealization> pr2 = pr
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.First());
If you need a specific object from the group, then you can order by another column
IQueryable<PerformanceRealization> pr2 = pr
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.OrderBy(x => x.SomeColumn).First());
for SomeColumn having the smallest value. For the greatest value, use OderByDescending instead.
Of course, you can integrate this approach into the first query:
IQueryable<PerformanceRealization> pr = _context.PerformanceRealization
.Where(u => u.Deadline == _context.PerformanceRealization
.Where(x => x.GroupRealizationId == u.GroupRealizationId)
.Max(x => x.Deadline)
)
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.OrderBy(x => x.SomeColumn).First());
Note, you don't need to have a Select at the end like .Select(u => u). Since it has no effect, you can just drop it.
If your EF Core version cannot handle it (as revealed in a comment), then transition to LINQ-to-Objects with AsEnumerable(), but do the filtering in EF Core to minimize the number of records sent to the front-end:
IQueryable<PerformanceRealization> pr = _context.PerformanceRealization
.Where(u => u.Deadline == _context.PerformanceRealization
.Where(x => x.GroupRealizationId == u.GroupRealizationId)
.Max(x => x.Deadline)
)
.AsEnumerable() // <===== transition from LINQ-to-EF-Core to LINQ-to-Objects
.GroupBy(x => x.GroupRealizationId)
.Select(g => g.OrderBy(x => x.SomeColumn).First());
After migrating to .NET 6 I am receiving following errors.
var subsQuery = context.SubscriptionUsers
.Where(x => subscritpionIds.Contains(x.SubscriptionId));
var subscriptionUsers = await context.Users
.Include(x => x.UserSettings)
.Join(subsQuery, u => u.Id, su => su.UserId, (u, su) => new { su.SubscriptionId, User = u })
.GroupBy(x => x.SubscriptionId)
.ToDictionaryAsync(x => x.Key, x => x.Select(x => x.User).ToList());
This code throws:
The LINQ expression ... 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'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I can't understand why it throws error, but hiding "GroupBy" part - solves it. My solution is this:
var subscriptionUsers = (await context.Users
.Include(x => x.UserSettings)
.Join(subsQuery, u => u.Id, su => su.UserId, (u, su) => new { su.SubscriptionId, User = u })
.ToListAsync())
.GroupBy(x => x.SubscriptionId)
.ToDictionary(x => x.Key, x => x.Select(x => x.User).ToList());
And I have another place, where I get same but different error:
var subscriptionsToSendTo = await context.Subscriptions
.Join(context.PricingPlans.Where(x => x.SystemName == "PromoOneUsd"), sub => sub.PricingPlanId, pp => pp.Id, (sub, pp) => sub)
.Include(x => x.SubscriptionUsers)
.ThenInclude(x => x.User)
.ThenInclude(x => x.UserSettings)
.Where(x =>
(x.EndDate < daysRangeFromNow && x.EndDate > DateTime.UtcNow) &&
(x.SubscriptionUsers.FirstOrDefault()
.User.UserSettings.FirstOrDefault(us =>
us.Name.Equals("ReceivedSevenDaysBeforeNinetyNineCentOfferExpires")
&& us.Value.Equals("true", StringComparison.InvariantCultureIgnoreCase)) == null
)
).ToListAsync();
Which throws:
The LINQ expression ... could not be translated. Additional information: Translation of the 'string.Equals' overload with a 'StringComparison' parameter is not supported. See https://go.microsoft.com/fwlink/?linkid=2129535 for more information. 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'. See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I fixed this with:
var subscriptionsToSendTo = await context.Subscriptions
.Join(context.PricingPlans.Where(x => x.SystemName == "PromoOneUsd"), sub => sub.PricingPlanId, pp => pp.Id, (sub, pp) => sub)
.Include(x => x.SubscriptionUsers)
.ThenInclude(x => x.User)
.ThenInclude(x => x.UserSettings)
.Where(x =>
(x.EndDate < daysRangeFromNow && x.EndDate > DateTime.UtcNow) &&
(x.SubscriptionUsers.FirstOrDefault()
.User.UserSettings.FirstOrDefault(us =>
us.Name.ToLower() == "receivedsevendaysbeforeninetyninecentofferexpires"
&& us.Value.ToLower() == "true") == null
)
).ToListAsync();
So I have questions:
Why first part throws exception?
Are my solutions alright? Any better solutions?
Regards
Why in the result "Titolare" is null?
If I don't use GroupBy, "Titolare" has value.
Thank you.
var ben = context.Benefici.Include("Titolare").Include("Titolare.ComuneDomicilio")
.Where(b => !b.Titolare.SD1_DAT_DECESSO.HasValue)
.OrderByDescending(b => b.SDB_DAT_INIZIO)
.GroupBy(b => b.SDB_CODDIS)
.ToList()
.Select(b => b.First())
.ToList();
It is because of GroupBy limitation - you cannot get grouped items using LINQ to Entities. It should be fixed in EF Core 6.
To get first item of the group, you have to rewrite your query. It is mimic of what will be generated by EF Core 6:
var itemsQuery = context.Benefici
.Where(b => !b.Titolare.SD1_DAT_DECESSO.HasValue);
var benQuery =
from u in itemsQuery.Select(b => new { b.SDB_CODDIS }).Distinct()
join b in itemsQuery
.Include(x => x.Titolare.ComuneDomicilio)
.Where(x => x.SDB_CODDIS == u.SDB_CODDIS)
.OrderByDescending(x => x.SDB_DAT_INIZIO)
.Take(1)
select b;
var ben = benQuery.ToList();
List<string> groupId = request.GroupId.Split(',').ToList();
ENTITIES.ProductGroup
.Where(p => p.IsDisplay)
.Where(p => p.FK_GroupNavigation.IsDisplay)
.Where(p => groupId.Any(g => g == (p.FK_Group ?? 0) + "")
.ToList();
The value in request.GroupId is "12,15" and the same values are in the table, but give the following error.
In Ef Core I want to search for some value in another list but it gives the following error What is the problem?
TargetFramework=5.0
The LINQ expression 'DbSet()
.Where(p => p.IsDisplay)
.LeftJoin(
inner: DbSet(),
outerKeySelector: p => EF.Property<Nullable>(p, "FK_Group"),
innerKeySelector: g => EF.Property<Nullable>(g, "PK_Group"),
resultSelector: (o, i) => new TransparentIdentifier<ProductGroup, Group>(
Outer = o,
Inner = i
))
.Where(p => p.Inner.IsDisplay)
.Count(p => __groupId_0
.Any(g => (g ?? "").Equals((object)(p.Outer.FK_Group ?? 0) + "")))' 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'.
Any with local collection is not translatable to SQL, use Contains instead. Also compare integers by integer values, query will use indexes if they are exists.
List<int> groupId = request.GroupId.Split(',').Slect(s => int.Parse(s)).ToList();
SGP_PRODUCT.ProductGroup
.Where(p => p.IsDisplay)
.Where(p => p.FK_GroupNavigation.IsDisplay)
.Where(p => groupId.Contains(p.FK_Group))
.ToList();
i have a somewhat complex structure i wont get into,
but what i try doing is:
Get all ShopItems, who's SourceItem has changed,
Get and update them according to their Source/Shop data.
i conjured the following:
var query = _ctx.ShopItems
.Include(si => si.Shop)
.Include(si=>si.SourceItem)
.Include(si => si.SourceItem.Source)
.Include(si=>si.Shop.ShopType)
.GroupBy(i => i.SourceItem)
.Where(g => g.Key.LastUpdate > lastUpdate)
.OrderBy(g => g.Key.LastUpdate)
.Take(updateCountLimit);
the query seems to work, but when itterating the Groups:
groupItem.Key.Source is null.
I somewhat solved it by Removing the Include()s, saving the Entities to an Array, and explicitly loading the references using
_ctx.Entry(updatedSourceItem.Key).Reference(src=>src.Source).Load();
How can i perform the query i want without round-tripping the DB for explicit loading ?
Not sure, but it's backwards to start with ShopItems and then group by SourceItem. Try just starting with SourceItem, something like
:
var query = _ctx.SourceItems
.Include(i => i.ShopItems)
.Include(i => i.Source)
.Include(i => i.ShopItems.Select( si => si.Shop))
.Include(i => i.ShopItems.Select( si => si.Shop).ShopType)
.Where(i => i.LastUpdate > lastUpdate)
.OrderBy(i => i.LastUpdate)
.Take(updateCountLimit);
//or
var query = _ctx.SourceItems
.Include("ShopItems")
.Include("Source")
.Include("ShopItems.Shops")
.Include("ShopItems.Shops.ShopType")
.Where(i => i.LastUpdate > lastUpdate)
.OrderBy(i => i.LastUpdate)
.Take(updateCountLimit);