I am migrating from .net core 2.2 to 3.0 and getting error for linq query
var accountList = someOtherList.Select(x => x.AccountNo).ToList();
var collectedAmount = await _dbContext.AllocPayments
.Where(p => accountList.Contains(p.AccountNo))
.SumAsync(x => x.Amount);
This is giving error:
System.InvalidOperationException : The LINQ expression
'DbSet
.Where(a => __accountList_0.Contains(a.AccountNo))
.Sum(a => a.Amount)' 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 either AsEnumerable(),
AsAsyncEnumerable(), ToList(), or ToListAsync(). See
https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
I read the documentation and can get it working by adding .ToListAsync() and evaluate it in client/.net, but then why cant this query be evaluated on server/sql server?
Related
I try to run this code here, in ASP.NET Entity Framework 7. The target is to have the most efficient solution here which should be a JOIN if the database.
public async Task<List<Building>> GetAllAsync(string commaSeparatedBuildingIDs)
{
var buildingRefIDs = commaSeparatedBuildingIDs.Split(",").ToList();
return await semiSoftDbContext.Buildings
.Join(buildingRefIDs, building => building.ReferenceId, refID => refID, (building, id) => building)
.ToListAsync();
}
I get the following error:
System.InvalidOperationException: The LINQ expression 'DbSet()
.Join(
inner: __p_0,
outerKeySelector: building => building.ReferenceId,
innerKeySelector: refID => refID,
resultSelector: (building, id) => building)' 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 already have tried several variations of join and read through the internet, but it says that ASP.Net should work with Join().
You should not join here (assuming you are using Entity Framework - AFAIK it does not handle quite a lot of operations with local collections, like joins), use Where with Contains:
return await semiSoftDbContext.Buildings
.Where(b => buildingRefIDs.Contains(b.ReferenceId))
.ToListAsync();
I want to check if a list contains any item from another list using EF Core with Npsql provider. Then I want to get the exact item that was matched in my Dto.
My code is the following (note: Reports.Models is List<string> and so is request.Models as well. The request is consumer filter/search):
var x = await _dbContext.Reports
.Where(x => x.Models.Any(i => request.Models.Contains(i)))
.Select(x => new ReportDto
{
// Model = x.Identifiers.First(i => request.Identifiers.Contains(i)) // this also fails.
Model = request.Models.First(i => request.Models.Any(y => y == i)), // fails on this line
})
.ToListAsync(cancellationToken);
I tried both ways using Any and Contains, neither work. They both return the same error which says:
System.InvalidOperationException: The LINQ expression 'i => __request_Models_0 .Contains(i)' 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.
But I don't understand why? The error never changes, even in my case when I use Any, it still complains about Contains.
You are effectively trying to push your request.Models to the database Server for it to evaluate if any of its datasets are in it. That won't work.
You need to request the Models from the database first and compare them locally OR transform your request.Models into a set of IDs that the database can compare against.
I am working on a C# application. I have to create a predicate for filtering data. I have a model class TissueItem which has a property named ExpirationData. I have to get that data from TissueItem where expiration date is less than or equal to number specified. My predicate expression is:
ExpressionStarter<TissueItem> predicate = PredicateBuilder.New<TissueItem>();
predicate = predicate.And(x =>
Convert.ToInt32((x.ExpirationDate.Value - DateTime.Today).TotalDays)
<= inventorySearchFilterModel.ExpirationStatus);
When i pass this predicate to get the data, i am getting the following exception:
The LINQ expression 'DbSet<TissueItem>()
.Where(t => Convert.ToInt32((t.ExpirationDate.Value - DateTime.Today).TotalDays) <= __inventorySearchFilterModel_ExpirationStatus_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'.
What can be the possible issue. I am using .NET Core 3.1.
Try this variant. Looks like EFC do not handle Timestamp.TotalDays.
var predicate = PredicateBuilder.New<TissueItem>();
predicate = predicate.And(x =>
EF.Functions.DateDiffDay(x.ExpirationDate.Value, DateTime.Today)
<= inventorySearchFilterModel.ExpirationStatus);
In .Net framework I had this working query:
IEnumerable<Cars> LatestCars = await _context.Cars.Where(x => x.IsActive == true && x.IsDeleted == false)
.GroupBy(y => y.ManufacturerId)
.Select(z =>
z.OrderByDescending(k => k.ReleaseDate)
.FirstOrDefault()
)
.OrderByDescending(l => l.ReleaseDate)
.Take(5)
.ToListAsync();
This basicly gets the latest 5 cars released by distinct manufacturers.
But when I switched to .NET Core. This query is not working anymore. And I have this error when I run it:
System.InvalidOperationException: The LINQ expression '(GroupByShaperExpression:
KeySelector: (g.ManufacturerId),
ElementSelector:(EntityShaperExpression:
EntityType: Cars
ValueBufferExpression:
(ProjectionBindingExpression: EmptyProjectionMember)
IsNullable: False
)
)
.OrderByDescending(p => p.ReleaseDate)' 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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync().
Do you have any suggestions? Thank you.
EF Core, starting from version 3, throws an exception when an expression could only be executed locally. And actually the problem is not the .OrderByDescending() per se, but the fact that the query contains grouping, and grouping only supports Select() projections that aggregate the result to a scalar. Because only this can be translated into a SQL GROUP BY statement.
There is one handy way of dealing with this. If you have a Manufacturer model which contains an IEnumerable<Car> Cars navigational property, you can start from there, and that leads to a translatable query.
So, in your case this working query could be the following:
Manufacturers.Select(m => m.Cars.OrderByDescending(c => c.ReleaseDate).FirstOrDefault())
.OrderByDescending(c => c.ReleaseDate).Take(5)
The downside is that you can have null values in this list, if a manufacturer has 0 cars, so normally it's a good idea to filter those out, but in this case the OrderByDescending() pretty much mitigates this.
Another possible solution is to query a limited number of items, and then continue working locally:
Cars.OrderByDescending(c => c.ReleaseDate).Take(100).ToList()
.GroupBy(c => c.ManufacturerId).Select(g => g.First()).Take(5)
The downside of this is that you can potentially end up having less than 5 results.
I have a problem querying PostgreSQL database using EF Core 3.1.
The query is very simple
var gamesQuery = this.dbContext.Games.Where(game => game.StartTime > DateTime.Now).AsQueryable();
// 'request.TimeFrom' is of type System.TimeSpan and the value is populated
gamesQuery = gamesQuery.Where(game => game.StartTime.TimeOfDay >= request.TimeFrom);
// .ToList()-int here causes the exception.
var games = gamesQuery.ToList();
The exception message clearly states that the query can not be translated:
"The LINQ expression 'DbSet\r\n .Where(g => g.StartTime > DateTime.Now)\r\n .Where(g => g.StartTime.TimeOfDay >= __request_TimeFrom_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 either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information."
The problem is that the same query works fine in .NET Core 2.2.
I haven't found anything about the problem yet.
Someone know what is the reason about this one or am I missing something?
Currently PostgreSQL EF Core 3.x query provider does not support translation of DateTime.TimeOfDay - see the TODO comment in the source code.
Most likely it "worked" in 2.x by silently using client evaluation. But implicit client evaluation has been removed in 3.0 and there is no way to turn it back on.
You can try the following equivalent construct:
.Where(game => (game.StartTime - game.StartTime.Date) >= request.TimeFrom)
At least it doesn't produce the aforementioned exception.
If it doesn't work, take their advice and switch explicitly to client evaluation by inserting AsEnumerable() in the appropriate place before the non translatable expression.
I haven't tried this yet but one solution could be to save TimeOfDay into database beside of DateTime property. Then you just compare it with your TimeSpan variable.