IQueryable<T>和IEnumerable< T> ?

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


另见与此问题重叠的IQueryable和IEnumerable有什么区别

209429 次浏览

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

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

查询执行:

  • 查询的执行将被执行“在process",通常所需要的是执行查询的每个部分的代码(作为代码)。

  • 在执行进程的地方,查询的逻辑必须用数据表示,以便LINQ提供程序可以将其转换为内存不足执行的适当形式——无论是LDAP查询、SQL查询还是其他查询。

更多:

http://www.codeproject.com/KB/cs/646361/WhatHowWhere.jpg

首先,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 . < / p >

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

表达式树在c#和。net平台上是一个非常重要的结构。(它们一般都很重要,但c#使它们非常有用。)为了更好地理解它们的区别,我建议阅读表达式语句之间的区别。对于lambda演算的高级理论概念,表达式支持将方法作为一级对象。IQueryable和IEnumerable的区别就在于这一点。IQueryable可以构建表达式树,而IEnumerable不能,至少对于我们这些不在微软秘密实验室工作的人来说不是一般意义上的表达式树。

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

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

这是一个很好的YouTube上的视频,它演示了这些接口的不同之处,值得一看。

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

要记住的第一个要点是IQueryable接口继承自IEnumerable,因此IEnumerable可以做的事情,IQueryable也可以做。

enter image description here

有很多不同之处,但让我们来讨论一个最大的不同,它造成了最大的不同。当你的集合使用LINQ或Entity框架加载并且你想对集合应用过滤器时,IEnumerable接口是有用的。

考虑下面的简单代码,它使用实体框架IEnumerable。它使用Where过滤器来获取EmpId2的记录。

EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees;
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();

此过滤器在IEnumerable代码所在的客户端执行。换句话说,所有的数据都是从数据库中获取的,然后在客户端进行扫描并获得EmpId2的记录。

enter image description here

但是现在看到下面的代码,我们已经将IEnumerable更改为IQueryable。它在服务器端创建一个SQL查询,只将必要的数据发送到客户端。

EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp =  emp.Where(x => x.Empid == 2).ToList<Employee>();

enter image description here

因此,IQueryableIEnumerable之间的区别在于在哪里执行筛选逻辑。一个在客户端执行,另一个在数据库上执行。

因此,如果你只使用内存中的数据收集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

现在我的目标是从数据库中的员工表中获得前2条记录。在Visual Studio (VS)中创建了一个新的c#控制台应用程序。然后,我添加了一个ADO。NET实体数据模型XML (EDMX)项指向数据库中的员工表。现在我可以开始编写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. 触发的查询总数:1

  2. < p >查询文本:

    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. 触发的查询总数:1

  2. SQL分析器捕获的查询文本:

    SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]
    

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

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

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

更详细的区别如下:

IEnumerable

  1. IEnumerable存在于System.Collections命名空间中
  2. IEnumerable在服务器端执行一个选择查询,在客户端加载内存中的数据,然后筛选数据
  3. IEnumerable适用于从List、Array等内存集合中查询数据
  4. IEnumerable有利于LINQ到对象和LINQ到XML查询

这个IQueryable

  1. IQueryable存在于System.Linq命名空间中
  2. IQueryable在服务器端执行一个带有所有过滤器的“选择查询”
  3. IQueryable适用于从内存外(如远程数据库,服务)集合查询数据
  4. IQueryable对于LINQ到SQL查询是有益的

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