您必须注意IEnumerable 和Iqueryable 之间的区别。
IEnumerable 对象表示对象序列。它包含所有要枚举的序列:你可以请求序列的第一个元素,一旦你有了一个元素,你就可以请求下一个元素,只要有下一个元素。
IQueryable 对象看起来像一个 IEnumerable,然而,它并不代表一个可枚举的序列,它代表了获得一个 IEnumerable 序列的可能性。
IQueryable 对象包含一个Expression 和一个Provider。 Expression 是一个通用描述,表示必须查询的内容。 Provider 知道谁将执行查询(通常是数据库管理系统)以及使用什么语言与此 DBMS 通信(通常是 SQL)。
如果您开始枚举 IQueryable,或者显式使用 GetEnumerator 和 MoveNext,或者通过调用 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 有点生疏。我想你会明白要点的)