EF Linq Error after change from dotnet Core 2.2.6 to 3.0.0

爱⌒轻易说出口 提交于 2020-01-09 10:40:02

问题


I'm trying to upgrade a solution to the new Core Framework 3.0.0. Now I'm having a small issue I don't understand.

Look, this method was unproblematic in 2.2.6:

public async Task<IEnumerable<ApplicationUser>> GetBirthdayUsersCurrentMonth()
    {
        return await ApplicationDbContext.Users
            .Where(x => x.Gender != ApplicationUser.GenderTypes.generic)
            .Where(x => x.BirthDate.GetValueOrDefault().Month == DateTime.Now.Month)
            .Where(x => x.RetireDate == null)
            .OrderBy(x => x.BirthDate.GetValueOrDefault())
            .ToListAsync();
    }

Now in 3.0.0 I get a Linq Error saying this:

InvalidOperationException: The LINQ expression 'Where( source: Where( source: DbSet, predicate: (a) => (int)a.Gender != 0), predicate: (a) => a.BirthDate.GetValueOrDefault().Month == DateTime.Now.Month)' 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()

When I disable this line:

.Where(x => x.BirthDate.GetValueOrDefault().Month == DateTime.Now.Month)

The error is gone but off course I get all users. And I can't see an error in this query. Could this perhaps be a bug in EF Core 3.0.0?


回答1:


The reason is that implicit client evaluation has been disabled in EF Core 3.

What that means is that previously, your code didn't execute the WHERE clause on the server. Instead, EF loaded all rows into memory and evaluated the expression in memory.

To fix this issue after the upgrade, first, you need to figure out what exactly EF can't translate to SQL. My guess would be the call to GetValueOrDefault(), therefore try rewriting it like this:

.Where(x => x.BirthDate != null && x.BirthDate.Value.Month == DateTime.Now.Month)



回答2:


As Daniel Hilgarth wrote his solution is fine and works. The Addition of Wiktor Zychla seems to work, too. I rewrote the method as follows:

public async Task<IEnumerable<ApplicationUser>> GetBirthdayUsersCurrentMonth()
    {
        return await ApplicationDbContext.Users
            .Where(x => x.Gender != ApplicationUser.GenderTypes.generic)
            //.Where(x => x.BirthDate.GetValueOrDefault().Month == DateTime.Now.Month)
            .Where(x => x.BirthDate.Value.Month == DateTime.Now.Month)
            .Where(x => x.RetireDate == null)
            .OrderBy(x => x.BirthDate)
            .ToListAsync();
    }

So, as it seems in Core 3.0.0 it's not a good idea to use as mentioned evaluation-methods event if these are standard methods served by the classes itself.

Thanks for your help.




回答3:


I had the same issue when i upgraded to efcore 3.0. What has changed in efcore 3.0 is that when he can not execute the query, he will just stop and throw an error.

The behaviour was the same if the previous versions of efcore, but when he did not recognized the parameters, he would just execute the query without the parameters (get more data then u wanted) but maybe you never noticed.

You can check that in the logs.

If you want to execute queries in efcore 3.0 you'll have to use fields in your query that are also in your db tables. He will not recognize object properties that are not mapped to de db

it's a pain right now to re-write queries but it will be a win in a while




回答4:


Make sure that your POCO class fields has explicitly defined getter and setter, for example

public class Devices
{
    public int Id { get; set; }
    public string SerialNumber { get; set; }
}


来源:https://stackoverflow.com/questions/58074844/ef-linq-error-after-change-from-dotnet-core-2-2-6-to-3-0-0

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!