IQueryable <T>和IEnumerable <T>有什么区别?

IQueryable<T>IEnumerable<T>什么区别?


另请参见与此问题重叠的IQueryable和IEnumerable之间有什么区别 。

首先, IQueryable<T> 扩展IEnumerable<T>接口,所以任何你可以用“plain” IEnumerable<T>做的事情,你也可以用IQueryable<T>

IEnumerable<T>只是一个GetEnumerator()方法,它返回一个Enumerator<T> ,你可以调用它的MoveNext()方法遍历一个T序列。

IQueryable<T>具有IEnumerable<T> 并不是特别指向查询提供者 (例如,LINQ to SQL提供者)的两个属性,而另一个指向代表IQueryable<T>查询expression式对象作为运行时遍历的抽象语法树,可以由给定的查询提供程序来理解(大部分情况下,您不能将一个LINQ to SQLexpression式提供给LINQ to Entities提供程序,而不会引发exception)。

expression式可以简单地是对象本身的一个常量expression式,也可以是一组复杂的查询操作符和操作数的树。 查询提供程序的IQueryProvider.Execute()IQueryProvider.CreateQuery()方法通过传递给它的expression式来调用,然后分别返回查询结果或另一个IQueryable

主要区别在于, IQueryable<T>的LINQ操作符使用Expression对象而不是委托,这意味着它接收的自定义查询逻辑(例如谓词或值select器)是以expression式树的forms而不是委托给方法。

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

查询执行:

  • 在执行查询的过程中 ,通常所有需要的是执行查询的每个部分的代码(作为代码)。

  • 如果执行是在进程外执行的,那么查询逻辑必须用数据表示,以便LINQ提供者可以将其转换为适合内存不足执行的适当forms – 无论是LDAP查询, SQL或其他。

更多信息:

  • LINQ: IEnumerable<T>IQueryable<T>
  • C#3.0和LINQ 。
  • “ 返回IEnumerable<T> vs IQueryable<T>
  • .NET和C#开发人员的反应式编程 – 对IEnumerableIQueryableIObservableIQbservable

KB/cs/646361/WhatHowWhere.jpg

这是我的Facebook页面上的一个很好的video ,演示了这些接口如何不同,值得一看。

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

要记住的第一个要点是IQueryable接口从IEnumerableinheritance,所以无论IEnumerable能做什么, IQueryable也可以。

在这里输入图像描述

有很多不同之处,但让我们讨论一下这个最大的区别。 使用LINQ或entity framework加载集合时, IEnumerable接口非常有用,并且您希望对集合应用filter。

考虑下面使用IEnumerable与entity framework的简单代码。 它使用Wherefilter来获取EmpId2logging。

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

此filter在IEnumerable代码所在的客户端执行。 换句话说,所有的数据都从数据库中提取出来,然后在客户端扫描,得到EmpId2的logging。

在这里输入图像描述

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

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

在这里输入图像描述

所以IQueryableIEnumerable之间的区别在于filter逻辑被执行的地方。 一个在客户端执行,另一个在数据库上执行。

因此,如果只处理内存中的数据收集, IEnumerable是一个不错的select,但是如果要查询与数据库连接的数据收集,那么IQueryable是一个更好的select,因为它减less了networkingstream量,并且使用了SQL语言的强大function。

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

IQueryable: IQueryable最适合于远程数据源,如数据库或Web服务(或远程查询)。 IQueryable是一个非常强大的function,可以实现各种有趣的延迟执行scheme(如基于分页和组合的查询)。

因此,当您只需遍历内存集合时,使用IEnumerable,如果您需要对集合(如Dataset和其他数据源)执行任何操作,请使用IQueryable

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

在现实生活中,如果你正在使用像LINQ到SQL这样的ORM

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

在这两种情况下,如果您不调用ToList()ToArray()那么查询将在每次使用时执行,因此,例如,您有一个IQueryable<T>并从中填充4个列表框,查询将针对数据库运行4次。

另外,如果你扩展你的查询:

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

然后用IQueryable生成的SQL将包含“where name =”a“,但是使用IEnumerable将会有更多的angular色从数据库中被撤回,然后x.name =”a“检查将由.NET完成。

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

这是我写在一个类似的职位(关于这个主题)。 (不,我通常不会引用自己,但是这些都是非常好的文章。)

“这篇文章是有用的: IQueryable与IEnumerable在LINQ到SQL 。

引用那篇文章,“根据MSDN文档,对IQueryable所做的调用通过构build内部expression式树来进行操作。 “这些扩展IQueryable(Of T)的方法不直接执行任何查询,而是它们的function是构build一个Expression对象,它是表示累积查询的expression式树。

expression式树在C#和.NET平台上是一个非常重要的构造。 (它们通常很重要,但C#使它们非常有用。)为了更好地理解这些差异,我build议阅读官方C#5.0规范中 expression式语句之间的区别。 对于分支到lambda微积分的高级理论概念,expression式支持方法作为第一类对象。 IQueryable和IEnumerable之间的区别就是围绕这一点。 IQueryable构buildexpression式树,而IEnumerable不能,至less对于我们这些不在微软的秘密实验室工作的人来说并不是这样。

这里是另一个非常有用的文章,详细介绍了推拉视angular的不同之处。 (通过“push”与“pull”,我指的是数据stream的方向。.NET和C#的反应式编程技术

这篇文章详细介绍了lambdaexpression式和lambdaexpression式之间的区别,并深入讨论了expression式tress的概念: 重温C#委托,expression式树和lambdaexpression式与lambdaexpression式。 “。

下面提到的小testing可能会帮助您理解IQueryable<T>IEnumerable<T>之间差异的一个方面。 我已经从这篇文章中转载了这个答案,我试图在其他人的post中添加更正

我在DB(DDL脚本)中创build了以下结构:

 CREATE TABLE [dbo].[Employee]([PersonId] [int] NOT NULL PRIMARY KEY,[Salary] [int] NOT NULL) 

这里是logging插入脚本(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表中获取前两个logging。 我添加了一个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分析器会话,这里是执行摘要:

  1. 查询总数:1
  2. 查询文本: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

只是IQueryable足够聪明,可以在数据库服务器端自身应用Top (2)子句,因此它只能通过线路传输5个logging中的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带来了Salary表中的所有5条logging,然后在客户端计算机上执行了内存过滤,以获得前2条logging。 所以更多的数据(在这种情况下是3个额外的logging)不必要的通过电线传输。

IEnumerable和IQueryable都用于保存数据的收集和执行数据处理操作,例如对数据集合进行过滤。 在这里你可以find与例子最好的区别比较。 http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html 在这里输入图像描述

ienumerable:当我们想要处理进程内存时,即没有数据连接。iqueryable:何时处理sql server,即与数据连接ilist:像add对象,删除对象等操作