为什么人们会写 IEnumerable 从内存中过滤数据,而 IQueryable 在服务器端过滤数据?

问题描述 投票:0回答:1

stackoverflow上有很多主题: 什么时候应该使用 IEnumerable,什么时候应该使用 IQueryable? IQueryable 和 IEnumerable 有什么区别? 什么时候应该使用 IEnumerable,什么时候应该使用 IQueryable? IQueryable 和 IEnumerable 有什么区别

人们都写到 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 在服务器端过滤数据呢?

c#
1个回答
0
投票

人们都写到 IEnumerable 从内存中过滤数据,而 IQueryable 在服务器端执行此操作。

当我们说“

IEnumerable
执行此操作”或“
IQueryable
执行此操作”时,我们并不是在谈论您将结果分配给的变量的类型。

  IEnumerable<Customer> customers = ...
//^^^^^^^^^^^^^^^^^^^^^
//not about this

它与正在使用的一组 LINQ 运算符有关。

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>
的某种类型的实例,这一事实是无关紧要的。

© www.soinside.com 2019 - 2024. All rights reserved.