无法翻译 LINQ 表达式,将在本地计算

Posted

技术标签:

【中文标题】无法翻译 LINQ 表达式,将在本地计算【英文标题】:The LINQ expression could not be translated and will be evaluated locally 【发布时间】:2019-09-10 14:24:54 【问题描述】:

我在 EntityFramework Core 中收到此警告,这是怎么回事?

我已经将 MSSQL 数据库设置为区分大小写。

Latin1_General_100_CS_AS

var test = await _context.Students
                .FirstOrDefaultAsync(m => m.LastName.Equals("ALEXANDER", StringComparison.InvariantCultureIgnoreCase));

Microsoft.EntityFrameworkCore.Query:警告:LINQ 表达式 '其中 [m].LastName.Equals("ALEXANDER", InvariantCultureIgnoreCase)' 无法翻译,将在本地进行评估。

【问题讨论】:

***.com/questions/841226/… 代码可以被评估为 SQL,因此它将在本地(即应用程序运行的地方)执行比较 @Scrobi 不能* 尝试使用以下方法:.FirstOrDefaultAsync(m => m.LastName.ToUpper().Equals("ALEXANDER")); 【参考方案1】:

您必须注意IEnumerableIqueryable 之间的区别。

IEnumerable 对象表示对象序列。它包含所有要枚举的序列:你可以请求序列的第一个元素,一旦你有了一个元素,你就可以请求下一个元素,只要有下一个元素。

IQueryable 对象看起来像一个 IEnumerable,然而,它并不代表一个可枚举的序列,它代表了获得一个 IEnumerable 序列的可能性。

IQueryable 对象包含一个Expression 和一个ProviderExpression 是一个通用描述,表示必须查询的内容。 Provider 知道谁将执行查询(通常是数据库管理系统)以及使用什么语言与此 DBMS 通信(通常是 SQL)。

如果您开始枚举 IQueryable,或者显式使用 GetEnumeratorMoveNext,或者通过调用 foreach、ToList、Max、FirstOrDefault 等隐式调用,这将在内部调用 GetEnumerator 和 MoveNext,表达式将发送到提供者,将其翻译成 SQL 并从 DBMS 获取数据。获取的数据以 IEnumerable 的形式返回,其中调用了 GetEnumerator 和 MoveNext。

所以在调用 GetEnumerator 和 MoveNext 之前不会执行查询。

这与我的问题有什么关系?

实体框架只能将类和方法转换为它知道的 SQL。实体框架不知道您自己的功能。事实上,有几个 LINQ 功能是实体框架不支持的。见Supported and Unsupported LINQ methods

不支持的方法之一是String.Equals(string, StringComparison)。如果你使用这个函数,编译器不会抱怨,因为编译器不知道你的实体框架版本支持哪些函数。因此你不会在编译时看到这个错误,你会在运行时看到它。

该错误告诉您在调用函数之前将首先获取数据。 这可能会导致效率低下的行为。

您的 LINQ 语句等于(省略 async-await,不是问题的一部分)

var test = dbContext.Students
    .Where(student => student.LastName.Equals("ALEXANDER", StringComparison.InvariantCultureIgnoreCase))
    .FirstOrDefault();
    

由于无法使用 Equals,警告说数据是在执行 Where 之前在本地获取的。因此,可能有几个不会通过 Where 的项目将从 DBMS 转移到您的本地进程。

如果您的数据库可以忽略大小写,请考虑将您的代码更改为:

var test = dbContext.Students
    .Where(student => student.LastName == "ALEXANDER")
    .FirstOrDefault();

这将产生类似于以下的 SQL 语句:

SELECT TOP 1 * from myDatabase.Students where LastName = "ALEXANDER"

(不确定这是否是正确的 SQL,因为我使用实体框架,所以我的 SQL 有点生疏。我想你会明白要点的)

【讨论】:

【参考方案2】:

EntityFramework 无法将 Equals("ALEXANDER", StringComparison.InvariantCultureIgnoreCase) 转换为 SQL,因此它会将所有 Student 表加载到内存中,然后搜索满足等式的第一个条目。

【讨论】:

你只是改写了异常信息,这不是解决办法。 是的,但 op 确认内容正在加载到内存中。

以上是关于无法翻译 LINQ 表达式,将在本地计算的主要内容,如果未能解决你的问题,请参考以下文章

LINQ 表达式“无法翻译”

EF.Property 抛出“无法翻译 LINQ 表达式”

无法翻译 LINQ 表达式 DbSet<>.Any

LINQ 表达式 - 使用 .Any in s Select 无法翻译

无法翻译 LINQ 表达式。以可翻译的形式重写查询,或切换到客户端评估 EF Core 3.1

Entityframework Core 3 linq表达式无法翻译