stackoverflow上有很多主题:
什么时候应该使用 IEnumerable,什么时候应该使用 IQueryable?
IQueryable
人们都写到 IEnumerable 从内存中过滤数据,而 IQueryable 在服务器端执行此操作。 但这完全不是真的。
IEnumerable 从内存中过滤数据仅当我们拆分查询时!!!
所以:
IEnumerable<Customer> customers = context.Customers.Where(c => c.FirstName.StartsWith("J")).Take(5).ToList();
它使用过滤器 top(5) 给出了正确的查询:
select top(5) * from Customers WHERE FirstName like 'j%';
但是:
IEnumerable<Customer> customers = context.Customers.Where(c => c.FirstName.StartsWith("J"));
var result = customers.Take(5).ToList(); //the filter is in a different line of code
它给出了一个没有 top(5) 的查询:
select * from Customers WHERE FirstName like 'j%';
那么为什么人们会写 IEnumerable 从内存中过滤数据,而 IQueryable 在服务器端过滤数据呢?
人们都写到 IEnumerable 从内存中过滤数据,而 IQueryable 在服务器端执行此操作。
当我们说“
IEnumerable
执行此操作”或“IQueryable
执行此操作”时,我们并不是在谈论您将结果分配给的变量的类型。
IEnumerable<Customer> customers = ...
//^^^^^^^^^^^^^^^^^^^^^
//not about this
Enumerable
声明在 IEnumerable<T>
上运行的 LINQ 运算符,而 Queryable
声明在 IQueryable<T>
上运行的 LINQ 运算符。前一个运算符在内存中操作,而后一个运算符将查询转换为 SQL 并在数据库上运行。
在第一个示例中,您没有“拆分”查询,
context.Customers
是 IQueryable
(大概)。您调用的Where
、Take
和ToList
都在Queryable
中声明。您声明 customers
为 IEnumerable<Customer>
类型的事实是无关紧要的。
在第二个示例中,未在
Take
上调用 IQueryable
。正如您所声明的,它在 customers
上调用,类型为 IEnumerable<Customer>
。因此,您最终会调用 Take
中声明的 Enumerable
,因此 Take
部分不会转换为 SQL。
请注意,LINQ 运算符都是扩展方法,因此不存在动态调度 - 调用哪个
Take
(Enumerable.Take
或 Queryable.Take
)取决于调用它的表达式的编译时类型。 customers
实际上存储了实现 IQueryable<T>
的某种类型的实例,这一事实是无关紧要的。