IQueryable<T>和IEnumerable<T>之间的区别是什么?


另见IQueryable和IEnumerable之间的区别是什么,与这个问题重叠。


主要的区别是IQueryable<T>的LINQ操作符接受表达式对象而不是委托,这意味着它接收的自定义查询逻辑,例如,谓词或值选择器,是表达式树的形式,而不是方法的委托。

IEnumerable<T>非常适合处理在内存中迭代的序列,但是 IQueryable<T>允许内存不足的事情,如远程数据源,如数据库或web服务。

查询执行:

查询的执行将在“进程中”执行,通常所需要的只是执行查询的每个部分的代码(作为代码)。 在将在进程外执行的地方,查询的逻辑必须用数据表示,以便LINQ提供程序可以将其转换为内存外执行的适当形式——无论是LDAP查询、SQL查询还是其他查询。

更多:

LINQ: IEnumerable<T> and IQueryable<T> c# 3.0和LINQ。 返回IEnumerable<T> vs IQueryable<T> 面向。net和c#开发人员的响应式编程——IEnumerable, IQueryable, IObservable和iqobservable的介绍 2008年:巴特·德·斯梅特的“年度最有趣的界面…可查询<T>”。


首先,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()方法通过传递给它的表达式被调用,然后分别返回一个查询结果或另一个IQueryable方法。


IEnumerable: IEnumerable最适合使用内存中的集合(或本地查询)。 IEnumerable不能在项目之间移动,它只是向前的集合。

这个IQueryable: IQueryable最适合远程数据源,如数据库或web服务(或远程查询)。 IQueryable是一个非常强大的特性,它支持各种有趣的延迟执行场景(比如分页和基于组合的查询)。

所以当你必须简单地遍历内存中的集合时,使用IEnumerable,如果你需要对集合做任何操作,如Dataset和其他数据源,使用IQueryable


IEnumerable引用了一个集合,而IQueryable只是一个查询,它将在表达式树中生成。我们将运行这个查询从数据库中获取数据。


简单地说,另一个主要的区别是IEnumerable在服务器端执行select查询,在客户端加载内存中的数据,然后过滤数据,而IQueryable在服务器端执行select查询,使用所有过滤器。


以下是我在类似的帖子(关于这个话题)上所写的内容。(不,我通常不引用自己的话,但这些都是非常好的文章。)

这篇文章很有帮助: LINQ-to-SQL中的IQueryable和IEnumerable。

引用那篇文章,“根据MSDN文档,对IQueryable调用通过构建内部表达式树来操作。 这些扩展IQueryable(Of T)的方法不直接执行任何查询。相反,它们的功能是构建Expression对象,该对象是表示累积查询的表达式树。“‘

Expression trees are a very important construct in C# and on the .NET platform. (They are important in general, but C# makes them very useful.) To better understand the difference, I recommend reading about the differences between expressions and statements in the official C# 5.0 specification here. For advanced theoretical concepts that branch into lambda calculus, expressions enable support for methods as first-class objects. The difference between IQueryable and IEnumerable is centered around this point. IQueryable builds expression trees whereas IEnumerable does not, at least not in general terms for those of us who don't work in the secret labs of Microsoft.

下面是另一篇非常有用的文章,从推和拉的角度详细介绍了两者的区别。(通过“push”和“。“拉”,我指的是数据流的方向。用于。net和c#的响应式编程技术

这是一篇非常好的文章,详细介绍了语句lambdas和表达式lambdas之间的区别,并更深入地讨论了表达式树的概念:重访c#委托、表达式树和lambda语句与lambda表达式。”


这是youtube上的一个很好的视频,它演示了这些界面的区别,值得一看。

下面是一个很长的描述性答案。

首先要记住的是IQueryable接口继承自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为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语言的力量。


在现实生活中,如果您正在使用LINQ-to-SQL之类的ORM

如果您创建了IQueryable查询,那么该查询可能会转换为sql并在数据库服务器上运行 如果您创建了一个IEnumerable,那么在运行查询之前,所有行都将作为对象拉入内存。

在这两种情况下,如果你不调用ToList()或ToArray(),那么查询将在每次使用它时执行,所以,比如说,你有一个IQueryable<T>,你从它填充4个列表框,那么查询将对数据库运行4次。

同样,如果你扩展你的查询:

q.Where(x.name = "a").ToList()

然后使用IQueryable生成的SQL将包含" where name = " a ",但是使用IEnumerable会从数据库中拉回更多的角色,然后. net将完成x.name = " a "检查。


Ienumerable:当我们想处理进程内内存时,即没有数据连接 可查询:何时处理SQL server,即数据连接 Ilist:添加对象、删除对象等操作


下面提到的小测试可能会帮助你理解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条记录。在Visual Studio (VS)中创建了一个新的c#控制台应用程序。然后,我添加了一个ADO。NET实体数据模型XML (EDMX)项指向数据库中的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查询分析器会话。以下是执行概要:

触发的查询总数:1 查询文本: SELECT TOP (2) [c]。[薪金]AS[薪金]来自[dbo]。[雇员]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分析器捕获的查询文本: 选择[Extent1]。[薪金]AS[薪金]来自[dbo]。[雇员]AS [Extent1]

现在需要注意的是,IEnumerable带来了Salary表中的所有5条记录,然后在客户端执行内存过滤以获得前2条记录。因此更多的数据(在本例中是3条额外的记录)通过网络传输,不必要地消耗了带宽。


IQueryable比IEnumerable更快,如果我们正在处理来自数据库的大量数据,因为IQueryable只从数据库中获取所需的数据,而IEnumerable无论是否需要从数据库中获取所有数据


我们使用IEnumerable和IQueryable来操作从数据库中检索的数据。IQueryable继承自IEnumerable,所以IQueryable包含了IEnumerable的所有特性。IQueryable和IEnumerable之间的主要区别是IQueryable使用过滤器执行查询,而IEnumerable先执行查询,然后根据条件过滤数据。

更详细的区别如下:

IEnumerable

IEnumerable在系统中存在。集合名称空间 IEnumerable在服务器端执行选择查询,在客户端加载内存中的数据,然后筛选数据 IEnumerable适用于从List、Array等内存集合中查询数据 IEnumerable有利于LINQ to Object和LINQ to XML查询

这个IQueryable

系统中存在IQueryable功能。Linq命名空间 IQueryable在服务器端执行一个带有所有过滤器的“选择查询” IQueryable适用于从内存外(如远程数据库,服务)集合中查询数据 IQueryable有利于LINQ到SQL的查询

所以IEnumerable通常用于处理内存中的集合,而IQueryable通常用于操作集合。