IQueryable<T>
扩展了 IEnumerable<T>
接口,因此您可以像使用“纯” IEnumerable<T>
一样使用 IQueryable<T>
。
IEnumerable<T>
只有一个 GetEnumerator()
方法,它返回一个 Enumerator<T>
,您可以调用其 MoveNext()
方法来迭代遍历 T 序列。
IQueryable<T>
拥有而 IEnumerable<T>
没有 的是两个特定的属性——其中一个指向一个查询提供程序(例如 LINQ to SQL 提供程序),另一个指向一个查询表达式,表示将 IQueryable<T>
对象作为运行时可遍历的抽象语法树,并且能够被给定的查询提供程序理解(基本上,您不能将一个 LINQ to SQL 表达式传递给一个 LINQ to Entities 提供程序,否则会引发异常)。IQueryProvider.Execute()
或 IQueryProvider.CreateQuery()
方法会传递一个 Expression,然后分别返回查询结果或另一个 IQueryable
。AsQueryable()
方法将只是把一个可枚举对象强制转换为 IQueryable
接口类型并返回它,否则会用 ConstantExpression
对象包装它,并在返回的 EnumerableQuery
对象中引用它。 - Mark CidadeIQueryable
接口继承自IEnumerable
,因此无论IEnumerable
能做什么,IQueryable
也可以做到。
IEnumerable
接口非常有用。IEnumerable
。它使用了一个Where
过滤器来获取EmpId
为2
的记录。EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees;
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
这里的筛选器在客户端执行,其中包含 IEnumerable
代码。换句话说,所有数据都从数据库获取,然后在客户端扫描并获取具有 EmpId
为 2
的记录。
IEnumerable
更改为IQueryable
。它在服务器端创建一个SQL查询,并仅将必要的数据发送到客户端。EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
IQueryable
和IEnumerable
之间的区别在于过滤逻辑执行的位置。一个在客户端执行,另一个在数据库中执行。IEnumerable
是一个不错的选择,但如果您想查询连接到数据库的数据集合,则IQueryable
是一个更好的选择,因为它减少了网络流量并利用了SQL语言的优势。IQueryable<T>
的 LINQ 运算符接收的是表达式树而不是委托,这意味着它所接收的自定义查询逻辑(例如谓词或值选择器)以表达式树的形式而不是方法委托的形式表示。
IEnumerable<T>
适用于在内存中迭代的序列处理,并且IQueryable<T>
允许处理外部数据源,例如远程数据源,如数据库或 Web 服务。更多内容请参见:
IEnumerable
, IQueryable
, IObservable
, 以及 IQbservable
IQUERYABLE<T>
"。IObservable<T>
的嘈杂图表出现,只有大约5%的图表涉及到IEnumerable<T>
和IQueryable<T>
;同样的情况也适用于“响应式编程”链接,其中IEnumerable<T>
/ IQueryable<T>
之间的区别仅作为介绍响应式扩展。此外,我建议包括一个指向Bart de Smet的今年最有趣的接口...IQueryable<T>
的链接。 - Zev SpitzIEnumerable: IEnumerable适用于处理内存中的集合(或本地查询)。 IEnumerable不会在项之间移动,它是一个只能向前移动的集合。
IQueryable: IQueryable适用于远程数据源,如数据库或Web服务(或远程查询)。 IQueryable是一个非常强大的功能,可以实现各种有趣的延迟执行场景(如分页和基于组合的查询)。
因此,如果您只需要迭代内存中的集合,请使用IEnumerable;如果您需要对集合进行任何操作(如Dataset和其他数据源),请使用IQueryable。
简单来说,另一个主要区别是 IEnumerable 在服务器端执行 select 查询,将数据加载到客户端内存中,然后过滤数据,而 IQueryable 则在服务器端执行带有所有筛选器的 select 查询。
在现实生活中,如果您正在使用像LINQ-to-SQL这样的ORM:
在这两种情况下,如果您没有调用ToList()
或ToArray()
,则每次使用查询时都会执行查询。例如,如果您有一个IQueryable<T>
并从中填充了4个列表框,则查询将针对数据库运行4次。
另外,如果您扩展查询:
q.Where(x.name = "a").ToList()
如果使用IQueryable,生成的 SQL 将包含“where name = 'a'”语句,但如果使用IEnumerable,将会从数据库中拉取更多记录,然后由 .NET 执行 x.name = 'a' 的检查。
IEnumerable
和 IQueryable
来操作从数据库检索出来的数据。 IQueryable
继承自 IEnumerable
,因此 IQueryable
包含了所有 IEnumerable
的特性。 IQueryable
与 IEnumerable
的主要区别在于,IQueryable
使用过滤器执行查询,而 IEnumerable
先执行查询,然后根据条件过滤数据。
以下是更详细的区别:
IEnumerable
IEnumerable
存在于 System.Collections
命名空间中IEnumerable
在服务器端执行选择查询,在客户端加载数据到内存中,然后过滤数据IEnumerable
适用于从内存集合(如 List、Array)查询数据IEnumerable
对于 LINQ to Object 和 LINQ to XML 查询非常有益IQueryable
IQueryable
存在于 System.Linq
命名空间中IQueryable
在服务器端执行带有所有过滤器的“select query”IQueryable
适用于从外部内存(如远程数据库、服务)集合查询数据IQueryable
对于 LINQ to SQL 查询非常有益通常情况下,IEnumerable
用于处理内存中的集合,而 IQueryable
则用于操纵集合。
以下提到的小测试可能有助于您理解 IQueryable<T> 和 IEnumerable<T> 之间差异的一个方面。我从此帖子中复制了这个答案,在那里我试图对别人的帖子进行更正。
我在数据库中创建了以下结构(DDL脚本):
CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL)
这是记录插入脚本(DML脚本):
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(1, 20)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(2, 30)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(3, 40)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(4, 50)
INSERT INTO [EfTest].[dbo].[Employee] ([PersonId],[Salary])VALUES(5, 60)
GO
现在我的目标是从数据库的表中获取前2条记录。我在Visual Studio (VS)中创建了一个新的C#控制台应用程序,然后添加了一个指向数据库中表的ADO.NET实体数据模型XML (EDMX)项。现在我可以开始编写LINQ查询。
情况I: IQueryable路由的代码
using (var efContext = new EfTestEntities())
{
IQueryable<int> employees = from e in efContext.Employees select e.Salary;
employees = employees.Take(2);
foreach (var item in employees)
{
Console.WriteLine(item);
}
}
在运行此程序之前,我已经在SQL Server实例上启动了一个SQL查询分析器会话。以下是执行摘要:
触发的查询总数:1
查询文本:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
我们可以看到,IQueryable 足够智能,能够在数据库服务器端自行应用 Top (2)
子句。因此,它仅通过网络带来了5条记录中的2条。客户端不再需要进行内存过滤。
情况二: IEnumerable 路由的代码
using (var efContext = new EfTestEntities())
{
IEnumerable<int> employees = from e in efContext.Employees select e.Salary;
employees = employees.Take(2);
foreach (var item in employees)
{
Console.WriteLine(item);
}
}
这个案例的执行摘要:
发出的查询总数: 1
在 SQL profiler 中捕获的查询文本:
SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]
需要注意的是,IEnumerable 会将 Salary 表中的所有 5 条记录带回客户端,然后在客户端进行内存过滤以获取前两条记录。因此,无谓地传输了更多数据(在这种情况下,额外的 3 条记录),并消耗掉了带宽。
IEnumerable指的是集合,而IQueryable只是一个查询,在表达式树内生成。我们将运行此查询以从数据库中获取数据。
以下是我在类似主题的帖子上写的内容(关于此主题)。 (不,我通常不引用自己,但这些是非常好的文章。)
"这篇文章很有帮助:LINQ-to-SQL中的IQueryable vs IEnumerable。
引用该文章,“根据MSDN文档,对IQueryable调用操作是通过构建内部表达式树来实现的。 “这些扩展IQueryable(Of T)的方法不直接执行任何查询。相反,它们的功能是构建一个表达式对象,即表示累积查询的表达式树。”'
表达式树是C#和.NET平台中非常重要的构造。 (它们在一般情况下也很重要,但C#使它们非常有用。)为了更好地理解区别,我建议阅读有关表达式和语句之间差异的官方C#5.0规范的差异。对于涉及lambda演算的高级理论概念,表达式使支持方法作为一级对象成为可能。 IQueryable和IEnumerable之间的区别集中在这一点上。IQueryable构建表达式树,而IEnumerable不会,至少对于我们这些不在Microsoft秘密实验室工作的人来说。
这是另一篇非常有用的文章,详细介绍了从推送vs.拉动的角度的差异。(通过“推送”与“拉动”,我指的是数据流的方向。用于.NET和C#的反应式编程技术
这是一篇非常好的文章,详细介绍了语句lambda和表达式lambda之间的差异,并讨论了表达式树的概念:重温C#委托,表达式树和lambda语句vs.lambda表达式。。”