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

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

问题描述

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

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

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:无法翻译 LINQ 表达式Last(DbSet)".以可翻译的形式重写查询,或通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用显式切换到客户端评估.有关详细信息,请参阅 https://go.microsoft.com/fwlink/?linkid=2101038.

解决方案

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

正如您在问题中提到的,微软在 这篇文章.

上述帖子的第一部分是:不再在客户端上评估 LINQ 查询".它说,在开发人员过去常常编写包含两个部分的查询之前;一部分是对数据库的查询,另一部分是只有客户端代码才知道的表达式.在这种情况下客户端对潜在昂贵表达式的评估只会触发警告.但在新版本中,EF core 只允许在客户端计算最后一次 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()//开始使用 LINQ to Objects(切换到客户端评估).Where(c => IsSpecialCustomer(c));

在上面的例子中,IsSpecialCustomer(c) 是一个不能转换为 SQL 的方法,因为它是一个 C# 方法,它只能在客户端代码中使用.所以开发者要么以可翻译的形式重写查询,要么查询数据库,然后使用 .AsEnumerable() 将数据库结果评估给客户端,然后可以根据 过滤结果IsSpecialCustomer(c) 返回值.这就是您仍然可以在代码中访问 AsEnumerable() 的原因.

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

嗯,造成这种情况的原因有两个.

我之前回答过第一个原因:检测不可组合 SQL 的代码已在 3.0 版中删除.

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

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

ef core 3 中的 40 个重大更改

公布实体框架核心 3.0 预览版 9 和实体框架 6.3 预览版 9

github 上的 EF 核心问题

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

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

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 ?

EDIT
Here's the exception:

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.

解决方案

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.

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

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.

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.

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

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.

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

Well, there is two reasons that causes this situation.

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

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:

40 breaking bad changes in ef core 3

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

EF core issues on github

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

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