繁体   English   中英

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

[英]The LINQ expression could not be translated and will be evaluated locally

我在 EntityFramework Core 中收到此警告有什么问题?

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

Latin1_General_100_CS_AS

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

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

您必须了解IEnumerableIqueryable之间的区别。

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

一个IQueryable对象看起来像一个 IEnumerable,但是,它并不代表一个可枚举的序列,它代表了获得一个 IEnumerable 序列的潜力。

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

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

因此,在调用 GetEnumerator 和 MoveNext 之前不会执行查询。

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

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

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

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

您的 LINQ 语句等于(省略异步等待,不是问题的一部分)

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 有点生疏。我想你会明白的)

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

在最后调用 ToListAsync 调用之前以错误的顺序查询我的 LINQ 方法,我得到了这个错误。

这是为我引发此错误的代码:

var sideeffects = await Context.SideEffects.Include(x => x.Language)
.Select(x => new SideEffect() { Name = x.Name, Language = x.Language, CleanName = x.CleanName, Id = x.Id, SideEffects = x.SideEffects, Related = x.Related, DrugSideEffects = x.DrugSideEffects })
.Where(x => !x.IsDeleted).ToListAsync();

在 select 和 include 之后调用 where 会搞砸查询并创建此错误。 当我将 where 子句移到开头时,它清除了错误并允许使用所有必填字段成功执行查询:

var sideeffects = await Context.SideEffects.Where(x => !x.IsDeleted)
.Include(x => x.Language)
.Select(x => new SideEffect() { Name = x.Name, Language = x.Language, CleanName = x.CleanName, Id = x.Id, SideEffects = x.SideEffects, Related = x.Related, DrugSideEffects = x.DrugSideEffects }).ToListAsync();

使用实体框架时要注意 LINQ 查询的顺序——尤其是在使用 Select 或 Include 时。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM