c# - C# - 从EF Core 2迁移到EF Core 3

将项目从(dotnet core 2/ ef core 2)升级到(dotnetcore 3/ ef core 3)后,几乎所有实体框架LINQ查询都被破坏了。

以下是一些我有问题的例子:


var league = await dbContext.League.LastAsync();



虽然这段代码在ef core 2中运行得很好,但是,它在ef core 3中抛出了异常,我能找到的唯一解决方法是下面的代码,但仍然不是我想要的,因为它不像以前那样异步。


var league = dbContext.League.AsEnumerable().Last();



引发相同异常的另一个例子是以下代码:


var user = await dbContext.User.FirstOrDefaultAsync(u =>


 u.UserId == userId && string.Equals(u.Token, token, StringComparison.InvariantCulture));



我仍然可以使用AsEnumerable(),但是,FirstOrDefault的异步版本不可用,所以这不能解决,

编辑
以下是例外:


System.InvalidOperationException: The LINQ expression 'Last<League>(DbSet<League>)' 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.



时间:

就像你在问题中提到的,微软对版本3.0中的更改有一个莫名其妙的描述,看这篇文章 。

上述文章的第一部分是: "LINQ查询不再在客户端上进行评估,在开发人员编写有两部分的查询之前,它说: 一部分是数据库查询,另一部分是客户端代码的表达式,在这种情况下 client evaluation of potentially expensive expressions only triggered a warning,但是在新版本中,EF内核仅允许在客户端上评估最后一次Select()调用,并且在无法转换为SQL或参数的表达式时引发异常。

让我们来看看一个由Diego Vega在他的EF Core 3.0公告博客上写的文章 。

显式切换到客户端: 如果查询基于无法转换为SQL的表达式筛选数据,则可能需要通过在查询中间插入对AsEnumerable(),AsAsyncEnumerable (),ToList ()或ToListAsync()的调用来显式地切换到客户端计算,例如,以下查询将不再在EF Core 3.0中工作,因为where子句中的某个谓词需要客户端评估:


var specialCustomers = context.Customers


 .Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));



但是,如果你知道在客户端上处理部分过滤器是可行的,你可以重写以下查询:


var specialCustomers = context.Customers


 .Where(c => c.Name.StartsWith(n)) 


 .AsEnumerable() // Start using LINQ to Objects (switch to client evaluation)


 .Where(c => IsSpecialCustomer(c));



上例中IsSpecialCustomer(c)是无法转换为SQL的方法,因为它是C#方法,仅在客户端代码中可用,因此开发人员应该重写查询,或者在数据库上查询数据库结果,然后根据.AsEnumerable()返回值,这就是为什么你仍然可以在你的代码中访问AsEnumerable()

现在,让我们来看看为什么FirstOrDefaultAsync()方法不可用?

导致这种情况的原因有两个,用于检测不可组合SQL的代码在3.0版本中被移除,第二个是: 查询管道不理解表达式树中的异步可查询运算符(例如: 当你尝试在EF.CompileQuery()上访问它时) 。

总之,你可以阅读以下几个有趣的帖子:

40 breaking bad changes in ef core 3

Announcing entity framework core 3.0 preview 9 and entity framework 6.3 preview 9

github上的EF Core问题

对某些属性使用OrderByDesc(),然后使用FirstAsync()

在没有过滤器的情况下在DbSet上调用AsEnumerable()会在本地下拉所有数据,而不是你要在生产中执行的操作。尝试重写上面的内容,并且监视生成的SQL,以确保你获得高性能的查询。

...