关于.NET: IQueryable 和IEnumerable的区别是什么?

What is the difference between IQueryable<T> and IEnumerable<T>?

IQueryableIEnumerable有什么区别?

另请参见与此问题重叠的iQuery和IEnumerable之间的区别。


首先,IQueryable扩展了IEnumerable接口,所以您可以用"普通"IEnumerable做任何事情,也可以用IQueryable做任何事情。

IEnumerable只是有一个GetEnumerator()方法,它返回一个Enumerator方法,您可以调用它的MoveNext()方法来迭代一个t序列。

IQueryable所说的IEnumerable不是两个属性,特别是一个指向查询提供程序(如linq to sql提供程序)的属性,另一个指向表示IQueryable对象的查询表达式的属性,它是一个运行时可遍历的抽象语法树,可以被给定的查询提供程序理解(对于大多数pART,如果不引发异常,则不能将LINQ to SQL表达式赋给LINQ to Entities提供程序)。

表达式可以是对象本身的常量表达式,也可以是由一组查询运算符和操作数组成的更复杂的树。调用查询提供程序的IQueryProvider.Execute()IQueryProvider.CreateQuery()方法,并向其传递表达式,然后分别返回查询结果或另一个IQueryable


主要的区别在于,IQueryable的LINQ运算符采用Expression对象而不是委托,这意味着它接收的自定义查询逻辑(例如谓词或值选择器)的形式是表达式树而不是方法委托。

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

查询执行:

  • 如果查询的执行将"进行中",通常只需要执行查询的每个部分的代码(作为代码)。

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

更多在:

  • Linq:IEnumerableIQueryable
  • C 3.0和LINQ。
  • "返回IEnumerableIQueryable"
  • 面向.NET和C开发人员的反应式编程-介绍IEnumerableIQueryableIObservableIQbservable

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


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

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

要记住的第一点是IQueryable接口继承自IEnumerable,所以无论IEnumerable能做什么,IQueryable也能做。

enter image description here

有很多不同之处,但让我们来讨论一个最大的不同之处。当使用LINQ或实体框架加载集合并且希望对集合应用筛选器时,IEnumerable接口非常有用。

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

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

在客户机端执行过滤器,其中IEnumerable代码为。换言之,所有数据都是从数据库中提取的,然后在客户机上进行扫描,用EmpId得到的记录是2

enter image description here

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

1
2
3
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语言的强大功能。


IEnumerable:IEnumerable最适合处理内存中的集合(或本地查询)。IEnumerable不在项之间移动,它是仅转发的集合。

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

因此,当必须简单地迭代内存中的集合时,请使用IEnumerable,如果需要对集合(如数据集和其他数据源)执行任何操作,请使用iQuery


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


在现实生活中,如果您使用像linq to sql这样的ORM

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

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

此外,如果扩展了您的查询:

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

然后,对于iQuery,生成的SQL将包含"where name="a",但是对于IEnumerable,将从数据库中提取更多的角色,然后x.name="a"检查将由.net完成。


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


下面提到的小测试可能有助于您理解IQueryableIEnumerable之间的区别。我在这篇文章中转载了这个答案,我试图在其他人的文章中添加更正。

我在数据库(DDL脚本)中创建了以下结构:

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

下面是记录插入脚本(DML脚本):

1
2
3
4
5
6
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查询。

可查询路由代码:

1
2
3
4
5
6
7
8
9
10
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) .[Salary] AS [Salary] FROM [dbo].[Employee] AS
  • 只是IQueryable足够聪明,可以在数据库服务器端本身应用Top (2)子句,所以它在5条记录中只带2条。客户端计算机完全不需要进一步的内存过滤。

    IEnumerable路由的代码:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    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事件探查器中捕获的查询文本:SELECT [Extent1].[Salary] AS [Salary]
    FROM [dbo].[Employee] AS [Extent1]
  • 现在的问题是,IEnumerableSalary表中的所有5条记录都带了进来,然后在客户机上执行内存过滤以获得前2条记录。因此,更多的数据(本例中还有3条记录)不必要地通过线路传输。


    这是我在一篇类似的文章(关于这个主题)上写的。(不,我通常不引用自己的话,但这些都是很好的文章。)

    "这篇文章很有帮助:linq to sql中的iqueryable与ienumerable。

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

    表达式树是C和.NET平台上非常重要的结构。(一般来说,它们很重要,但C使它们非常有用。)为了更好地理解这一区别,我建议阅读官方C 5.0规范中表达式和语句之间的差异。对于分支到lambda微积分的高级理论概念,表达式支持将方法作为一级对象。iqueryable和IEnumerable之间的区别集中在这一点上。iqueryable构建表达式树,而IEnumerable不构建表达式树,至少对于我们这些不在微软秘密实验室工作的人来说不构建表达式树。

    这是另一篇非常有用的文章,从推和拉的角度详细说明了不同之处。(通过"推"和"拉",我指的是数据流的方向。.NET和C的反应式编程技术#

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


    我们使用IEnumerable和IQueryable来操作从数据库中检索到的数据。IEnumerable继承自IQueryable,因此IQueryable确实包含所有IEnumerable功能。iqueryable和IEnumerable的主要区别在于,iqueryable使用过滤器执行查询,而IEnumerable首先执行查询,然后根据条件过滤数据。

    在下面找到更详细的区别:

    可枚举的

  • System.Collections命名空间中存在IEnumerable。
  • IEnumerable在服务器端执行选择查询,在客户端将数据加载到内存中,然后筛选数据。
  • IEnumerable适用于从内存中的集合(如列表、数组)查询数据。
  • IEnumerable有助于LINQ to Object和LINQ to XML查询。
  • 可查询的

  • IQueryable存在于System.Linq命名空间中。
  • iqueryable在服务器端执行带有所有筛选器的"select查询"。
  • iQueryable适用于从内存外(如远程数据库、服务)集合查询数据。
  • IQueryable有助于LINQ to SQL查询。
  • 因此,IEnumerable通常用于处理内存中的集合,而iQueryable通常用于操作集合。


    IEnumerable和IQueryable都用于保存数据收集,并执行数据操作操作操作,例如对数据收集进行筛选。在这里,您可以找到与示例的最佳差异比较。http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.htmlenter image description here


    如果我们处理来自数据库的大量数据,iqueryable比iEnumerable更快,因为iqueryable只从数据库中获取所需数据,而iEnumerable从数据库中获取所有数据,而不管是否需要。


    IEnumerable:当我们想要处理进程内内存时,即不需要数据连接iqueryable:何时处理SQL Server,即数据连接ilist:添加对象、删除对象等操作