从EF Core 2迁移到EF Core 3 [英] Migrating from EF Core 2 to EF Core 3

查看:626
本文介绍了从EF Core 2迁移到EF Core 3的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

将我的项目从(dotnet核心2/ef核心2)升级到(dotnet核心3/ef核心3)后,几乎所有我的实体框架LINQ查询都被破坏了.虽然我已经阅读目前尚不清楚该怎么做.

After upgrading my project from (dotnet core 2/ef core 2) to (dotnet core 3/ef core 3) almost all of my entity framework LINQ queries are broken. while I already read this it's still unclear to know what to do.

以下是一些我遇到问题的示例:

Here are some examples that I have problem with:

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

虽然此代码在ef内核2中运行良好,但在ef内核3中引发了异常.我能找到的唯一解决方法是以下代码,因为它与以前不一样,所以仍然不是我想要的.

While this code worked just fine in ef core 2 it throws exception in ef core 3. The only workaround I could find about this was the following code which is still not what I want since it's not async like before.

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

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

Another example that throws the same exception is the following code:

var user = await dbContext.User.FirstOrDefaultAsync(u =>
                u.UserId == userId && string.Equals(u.Token, token, StringComparison.InvariantCulture));

我仍然可以使用AsEnumerable(),但是那里没有可用的FirstOrDefault异步版本,所以这不是一个选择.有人可以指导我吗?

I still can use AsEnumerable() but the async version of FirstOrDefault is not available there so that's not an option. can somebody guide me with this ?

编辑
例外:

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.

推荐答案

您的问题的答案将是非常冗长的,因为它对应于EF Core 3.0中发生的一些不同更改.因此,我们只考虑其中的一小部分.

Answer to your question is going to be really verbose because it's corresponds to some different changes happened in EF Core 3.0; So, let's just consider a little part of it.

正如您在问题中提到的那样,Microsoft在

As you've mentioned in your question, microsoft has a somehow confusing description about the changes on version 3.0 in this post.

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

The first part of the above post is: 'LINQ queries are no longer evaluated on the client'. It says, before developers used to write queries that have two parts in it; One part, was a query on database, and another part was an expression that was only know for client code. In this situation client evaluation of potentially expensive expressions only triggered a warning. But in the new version, EF core only allows the last Select() call to be evaluated on the client, and throws an exception when there is expressions that cannot be converted to either SQL or parameter.

为清楚起见,让我们看一下迭戈·维加(Diego Vega)在其

To clear this part up let's take a look at an example described by Diego Vega in his EF Core 3.0 announcement blog post.

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

Switch to client evaluation explicitly: If your query filters data based on an expression that cannot be translated to SQL, you may need to switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync() in the middle of the query. For example, the following query will no longer work in EF Core 3.0 because one of the predicates in the where clause requires client evaluation:

var specialCustomers = context.Customers
    .Where(c => c.Name.StartsWith(n) && IsSpecialCustomer(c));

但是,如果您知道在客户端上处理部分过滤器是合理的,则可以将查询重写为:

But if you know it is reasonable to process part of the filter on the client, you can rewrite the query as:

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()向客户端评估数据库结果,然后可以根据IsSpecialCustomer(c)返回值过滤结果. 这就是为什么您仍然可以在代码中访问AsEnumerable()的原因.

In the above example IsSpecialCustomer(c) is a method that cannot be converted to SQL because it's a C# method that it's only available in client code. So developers should either rewrite the query in a form that can be translated, or query on database and then evaluate database results to client using .AsEnumerable() and then It's possible to filter results based on IsSpecialCustomer(c) returned value. This is why still you can access AsEnumerable() in your code.

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

Now, let's peek on why FirstOrDefaultAsync() method is not available?

嗯,有两种原因导致这种情况.

Well, there is two reasons that causes this situation.

我已经回答了第一个原因:在3.0版中删除了用于检测不可组合SQL的代码.

I've answered first reason before: The code to detect non-composable SQL was removed in version 3.0.

第二个是:查询管道无法理解表达式树中的异步可查询运算符(例如:当您尝试在 EF.CompileQuery() 上访问它时).

And the second one is: query pipeline does not understand async queryable operators in the expression tree (e.g.: when you're trying to access it on EF.CompileQuery()).

总而言之,您可以阅读一些有趣的帖子:

All in all, there is a couple of interesting posts you can read:

在ef核心3中打破了40个重大更改

github上的EF核心问题

这篇关于从EF Core 2迁移到EF Core 3的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆