IQueryable<T>
和 和有什么不一样IEnumerable<T>
?
另请参阅与此问题重叠的IQueryable 和 IEnumerable 之间有什么区别。
首先,扩展接口,所以你可以用“普通”做任何事情,你也可以用.IQueryable<T>
IEnumerable<T>
IEnumerable<T>
IQueryable<T>
IEnumerable<T>
只是有一个GetEnumerator()
返回 an 的方法,Enumerator<T>
您可以调用它的MoveNext()
方法来迭代一系列T。
IQueryable<T>
没有的IEnumerable<T>
特别是两个属性——一个指向查询提供程序(例如,LINQ to SQL 提供程序),另一个指向将对象表示为运行时可遍历的抽象语法树的查询表达式IQueryable<T>
。由给定的查询提供程序理解(在大多数情况下,您不能将 LINQ to SQL 表达式提供给 LINQ to Entities 提供程序而不引发异常)。
表达式可以简单地是对象本身的常量表达式,也可以是由一组查询运算符和操作数组成的更复杂的树。使用传递给它的表达式调用查询提供程序IQueryProvider.Execute()
或IQueryProvider.CreateQuery()
方法,然后分别返回一个查询结果或另一个。IQueryable
主要区别在于用于IQueryable<T>
获取Expression
对象而不是委托的 LINQ 运算符,这意味着它接收的自定义查询逻辑(例如谓词或值选择器)采用表达式树的形式而不是方法的委托。
IEnumerable<T>
非常适合处理在内存中迭代的序列,但是IQueryable<T>
允许内存不足的东西,例如远程数据源,例如数据库或 Web 服务。查询的执行将在“进程中”执行,通常只需要代码(作为代码)来执行查询的每个部分。
如果执行将在进程外执行,则查询的逻辑必须在数据中表示,以便 LINQ 提供程序可以将其转换为内存外执行的适当形式 - 无论是 LDAP 查询, SQL 什么的。
更多内容:
IEnumerable<T>
和IQueryable<T>
IEnumerable<T>
vsIQueryable<T>
”IEnumerable
介绍IQueryable
IObservable
IQbservable
IQUERYABLE<T>
”来自Bart De Smet。这是youtube 上的一个很好的视频,展示了这些界面的不同之处,值得一看。
下面是一个很长的描述性答案。
要记住的第一个重点是IQueryable
interface 继承自IEnumerable
,所以能做什么IEnumerable
也IQueryable
能做什么。
有很多不同之处,但让我们讨论一个最大的不同之处。当您的集合使用实体框架加载并且您想对集合应用过滤器时,IEnumerable
界面很有用。LINQ
考虑以下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
is获取记录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 语言的强大功能。
IEnumerable: IEnumerable is best suitable for working with in-memory collection (or local queries). IEnumerable doesn’t move between items, it is forward only collection.
IQueryable: IQueryable best suits for remote data source, like a database or web service (or remote queries). IQueryable is a very powerful feature that enables a variety of interesting deferred execution scenarios (like paging and composition based queries).
So when you have to simply iterate through the in-memory collection, use IEnumerable, if you need to do any manipulation with the collection like Dataset and other data sources, use IQueryable
简而言之,其他主要区别在于 IEnumerable 在服务器端执行选择查询,在客户端加载内存中的数据,然后过滤数据,而 IQueryable 在服务器端使用所有过滤器执行选择查询。
在现实生活中,如果您使用的是像 LINQ-to-SQL 这样的 ORM
在这两种情况下,如果您不调用 a ToList()
or ToArray()
then 查询将在每次使用时执行,例如,您有 anIQueryable<T>
并从中填充 4 个列表框,那么查询将针对数据库运行 4 次。
此外,如果您扩展您的查询:
q.Where(x.name = "a").ToList()
然后使用 IQueryable 生成的 SQL 将包含“where name = “a”,但是使用 IEnumerable 将从数据库中拉回更多角色,然后 x.name = “a” 检查将由 .NET 完成。
下面提到的小测试可能会帮助您了解IQueryable<T>
和之间差异的一个方面IEnumerable<T>
。我已经从这篇文章中复制了这个答案,我试图在其他人的帖子中添加更正
我在 DB(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
Employee
现在,我的目标是简单地从数据库中的表中获取前 2 条记录。我在控制台应用程序中添加了一个 ADO.NET 实体数据模型项,指向Employee
我的数据库中的表,并开始编写 LINQ 查询。
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 Query profiler 会话,下面是执行摘要:
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);
}
}
本案执行总结:
SELECT [Extent1].[Salary] AS [Salary]
FROM [dbo].[Employee] AS [Extent1]
现在事情是IEnumerable
把表中存在的所有 5 条记录都带入Salary
,然后在客户端计算机上执行内存过滤以获得前 2 条记录。所以更多的数据(在这种情况下是 3 个额外的记录)不必要地通过网络传输。
IEnumerable 指的是一个集合,但 IQueryable 只是一个查询,它将在表达式树中生成。我们将运行此查询以从数据库中获取数据。
我们使用IEnumerable
和IQueryable
操作从数据库中检索到的数据。IQueryable
继承自IEnumerable
,因此IQueryable
包含所有IEnumerable
功能。IQueryable
和之间的主要区别在于IEnumerable
,IQueryable
使用过滤器执行查询,而IEnumerable
先执行查询,然后根据条件过滤数据。
在下面找到更详细的区别:
IEnumerable
IEnumerable
存在于System.Collections
命名空间中IEnumerable
在服务器端执行选择查询,在客户端加载内存中的数据,然后过滤数据IEnumerable
适用于从内存集合中查询数据,如 List、ArrayIEnumerable
有利于 LINQ to Object 和 LINQ to XML 查询可查询的
IQueryable
存在于System.Linq
命名空间中IQueryable
使用所有过滤器在服务器端执行“选择查询”IQueryable
适用于从内存外(如远程数据库、服务)集合中查询数据IQueryable
有利于 LINQ to SQL 查询所以IEnumerable
通常用于处理内存中的集合,而IQueryable
通常用于操作集合。
这是我在类似的帖子(关于这个主题)上写的。(不,我通常不引用自己的话,但这些都是非常好的文章。)
编辑:删除了一篇文章的链接,该文章曾经很有帮助,但现在重定向到色情网站。(感谢@Grace 指出这一点!)
引用那篇文章(标题为“LINQ-to-SQL 中的 IQueryable 与 IEnumerable”),“根据 MSDN 文档,对 IQueryable 进行的调用是通过构建内部表达式树来操作的。“这些扩展 IQueryable(Of T) 的方法不直接执行任何查询。相反,它们的功能是构建一个 Expression 对象,这是一个表示累积查询的表达式树。”'
表达式树是 C# 和 .NET 平台上非常重要的构造。(它们通常很重要,但 C# 使它们非常有用。)为了更好地理解差异,我建议在此处阅读官方 C# 5.0 规范中的表达式和语句 之间的差异。对于分支到 lambda 演算的高级理论概念,表达式支持将方法作为一等对象。IQueryable 和 IEnumerable 之间的区别集中在这一点上。IQueryable 构建表达式树,而 IEnumerable 没有,至少对于我们这些不在微软秘密实验室工作的人来说不是一般意义上的。
这是另一篇非常有用的文章,详细介绍了推与拉的区别。(通过“推”与“拉”,我指的是数据流的方向。.NET 和 C# 的反应式编程技术
这是一篇非常好的文章,详细介绍了语句 lambda 和表达式 lambda 之间的区别,并更深入地讨论了表达式树的概念:[重新审视 C# 委托、表达式树和 lambda 语句与 lambda 表达式。][4]。”
如果我们要处理来自数据库的大量数据,IQueryable 比 IEnumerable 更快,因为 IQueryable 只从数据库中获取所需的数据,而 IEnumerable 则从数据库中获取所有数据,而不管是否需要
ienumerable:当我们要处理进程内内存时,即没有数据连接 iqueryable:何时处理sql server,即有数据连接 ilist :添加对象、删除对象等操作