Queries can't be translated - c#

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

Related

GroupBy in subquery with MAX() in C#

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());

Could not be translated. Either rewrite the query in a form that can be translated,

I have C# application (.NET Core 6) and I have written the following LINQ expression.
var data = query.OrderByDescending(a => a.CreatedOn).GroupBy(b => new { b.PackageID, b.PatientId }).ToList();
I get following error
The LINQ expression 'DbSet<LAB_ValueBasedResult>()
.Where(item => item.GroupId == 58)
.Where(item => item.HospitalId == 59)
.Where(x => x.IsActive)
.Where(x => x.CreatedOn >= __AddDays_0)
.Where(x => x.CreatedOn <= __AddDays_1)
.Where(x => __lstPatientID_2.Contains(x.PatientId))
.OrderByDescending(a => a.CreatedOn)
.GroupBy(b => new {
PackageID = b.PackageID,
PatientId = b.PatientId
})' 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 want to Add OrderByDescending and GroupBy in LINQ execute. how could I do it?
Please advise how can I resolve this.
Thank you.

The LINQ expression cannot be translated on Grouping

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

Find in Entity Framework multiple OR parameters

Suppose I have a product in my database with the description “white shirt size 50”.
The search parameter would be “shirt 50”. I have a more complex query in which I add several “OR”s and I can't get them to work.
I get the following error:
The LINQ expression
'DbSet()
.Where(p => p.IdTienda == __request_IdTienda_0)
.Join(
inner: DbSet(),
outerKeySelector: p => p.IdArticulo,
innerKeySelector: a => a.Id,
resultSelector: (p, a) => new TransparentIdentifier<Publicacion, Articulo>(
Outer = p,
Inner = a
))
.Where(ti => __arrayrequest_1
.Any(s => ti.Outer.Descripcion.Contains(s)) || ti.Outer.Codigo == __request_Filtro_SearchText_2 || ti.Inner.Codigo == __request_Filtro_SearchText_2 || ti.Inner.CodigoUniversal == __request_Filtro_SearchText_2 || ti.Inner.CodigoUniversalBulto == __request_Filtro_SearchText_2)'
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.
My code so far is the following:
var arrayrequest = request.Filtro.SearchText.Split().ToList();
var query = from publicacion in _dbContext.Publicaciones.Where(p => p.IdTienda == request.IdTienda)
join articulo in _dbContext.Articulos
on publicacion.IdArticulo equals articulo.Id
where
arrayrequest.Any(s => publicacion.Descripcion.Contains(s))
|| publicacion.Codigo == request.Filtro.SearchText
|| articulo.Codigo == request.Filtro.SearchText
|| articulo.CodigoUniversal == request.Filtro.SearchText
|| articulo.CodigoUniversalBulto == request.Filtro.SearchText
select publicacion;
var publicaciones = await query
.Include(p => p.Articulo)
.Include(p => p.TributoPublicacion)
.ToArrayAsync();
The error occurs in the section
arrayrequest.Any(s => publicacion.Descripcion.Contains(s))`
I use Entity Framework Core 5 - any help is welcome
Don't want to repeat myself, but it is good to show how it can be solved.
EF do not supports complex predicates with local collections and here you need to build expression tree dynamically. This answer has GetItemsPredicate function which helps in building needed condition.
Then you can rewrite your query in this way:
var arrayrequest = request.Filtro.SearchText.Split().ToList();
var query = from publicacion in _dbContext.Publicaciones.Where(p => p.IdTienda == request.IdTienda)
join articulo in _dbContext.Articulos
on publicacion.IdArticulo equals articulo.Id
select publicacion;
var descriptionPredicate = query.GetItemsPredicate(arrayrequest, (publicacion, s) => publicacion.Descripcion.Contains(s));
Expression<Func<Publicacion, bool>> otherPredicate = publicacion => publicacion.Codigo == request.Filtro.SearchText
|| articulo.Codigo == request.Filtro.SearchText
|| articulo.CodigoUniversal == request.Filtro.SearchText
|| articulo.CodigoUniversalBulto == request.Filtro.SearchText;
query = query.Where(descriptionPredicate.CombineOr(otherPredicate)));
var publicaciones = await query
.Include(p => p.Articulo)
.Include(p => p.TributoPublicacion)
.ToArrayAsync();

Problem in Search From One List in Another List in Ef .Net Core

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();

Categories

Resources