LINQ 表达式无法翻译,将在本地进行评估 [英] The LINQ expression could not be translated and will be evaluated locally

查看:34
本文介绍了LINQ 表达式无法翻译,将在本地进行评估的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 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 表达式'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,Expression 被发送到 Provider,Provider 将把它翻译成 SQL 并从 DBMS 中获取数据.获取的数据作为 IEnumerable 返回,其中调用 GetEnumerator 和 MoveNext.

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

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

实体框架只能将类和方法转换为它知道的 SQL.实体框架不知道您自己的功能.事实上,实体框架不支持多种LINQ函数.请参阅 支持和不支持的 LINQ 方法

不支持的方法之一是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 有点生疏.我想你会明白要点)

Im getting this WARNING in EntityFramework Core what is wrong?

I already set MSSQL Datebase to Case Sensitive.

Latin1_General_100_CS_AS

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

Microsoft.EntityFrameworkCore.Query:Warning: The LINQ expression 'where [m].LastName.Equals("ALEXANDER", InvariantCultureIgnoreCase)' could not be translated and will be evaluated locally.

解决方案

You have to be aware of the difference between IEnumerable and Iqueryable.

An IEnumerable object represents a sequence of objects. It holds everything to enumerate over this sequence: you can ask for the first element of the sequence, and once you've got an element you can ask for the next one, as long as there is a next one.

An IQueryable object seems like an IEnumerable, however, it does not represent an enumerable sequence, it represents the potential to get an IEnumerable sequence.

The IQueryable object holds an Expression and a Provider. The Expression is a generic description expressing what must be queried. The Provider knows who will execute the query (usually a database management system) and what language is used to communicate with this DBMS (usually SQL).

If you start enumerating an IQueryable, either explicitly using GetEnumerator and MoveNext, or implicitly by calling foreach, ToList, Max, FirstOrDefault, etc, which will deep inside call GetEnumerator and MoveNext, the Expression is sent to the Provider, who will translate it into SQL and fetch the data from the DBMS. The fetched data is returned as an IEnumerable, of which the GetEnumerator and MoveNext are called.

So the query is not executed before you call GetEnumerator and MoveNext.

What does this have to do with my question?

Entity framework can only convert classes and methods to SQL that it knows about. Entity Framework does not know your own functions. In fact, there are several LINQ function that are not supported by entity framework. See Supported and Unsupported LINQ methods

One of the unsupported methods is String.Equals(string, StringComparison). If you use this function, the compiler can't complain, because the compiler does not know what functions are supported by your version of entity framework. Therefore you won't see this error at compile time, you'll see it at runtime.

The error tells you that the data will first be fetched before the function is called. This might lead to inefficient behaviour.

Your LINQ statement is equal to (leave out the async-await, not part of the problem)

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

Since Equals can't be used, the warning says that the data is fetched locally before the Where is executed. So it might be that several items that will not pass the Where will be transferred from the DBMS to your local process.

If your database can ignore case sensitivity, consider changing your code to:

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

This will result in a SQL statement similar to:

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

(not sure if this is correct SQL, since I use entity framework my SQL is a bit rusty. I guess you'll get the gist)

这篇关于LINQ 表达式无法翻译,将在本地进行评估的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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