¿Cuál es la diferencia entre IQueryable <T> e IEnumerable <T>?

Respuestas:

258

En primer lugar, extiende la interfaz, por lo que todo lo que puede hacer con un "plano" , también puede hacerlo con un .IQueryable<T> IEnumerable<T>IEnumerable<T>IQueryable<T>

IEnumerable<T>Sólo tiene un GetEnumerator()método que devuelve una Enumerator<T>para los que pueden llamar su MoveNext()método de repetición de una secuencia de T .

Lo IQueryable<T>que tiene eso IEnumerable<T> no son dos propiedades en particular: una que apunta a un proveedor de consultas (por ejemplo, un proveedor LINQ to SQL) y otra que apunta a una expresión de consulta que representa el IQueryable<T>objeto como un árbol de sintaxis abstracta que se puede recorrer en tiempo de ejecución y que puede ser entendido por el proveedor de consultas dado (en su mayor parte, no puede dar una expresión LINQ to SQL a un proveedor LINQ to Entities sin que se produzca una excepción).

La expresión puede ser simplemente una expresión constante del objeto en sí o un árbol más complejo de un conjunto compuesto de operadores de consulta y operandos. El proveedor IQueryProvider.Execute()o los IQueryProvider.CreateQuery()métodos de consulta se invocan con una Expresión que se le pasa, y luego IQueryablese devuelve un resultado de consulta u otro , respectivamente.

Mark Cidade
fuente
8
¿Hay algún beneficio al usar AsQueryable?
Jordan
66
El único beneficio es la conveniencia. AsQueryable()solo lanzará un enumerable a un consultable y lo devolverá si implementa la IQueryableinterfaz; de lo contrario, lo envuelve en un ConstantExpression, al que se hace referencia en un EnumerableQueryobjeto devuelto .
Mark Cidade
3
Pregunta relacionada: ¿ IEnumerable <T> y IQueryable <T> aclaración?
Christopher Stevenson el
1
Vale la pena leer este artículo
JenonD
El enlace @JenonD está muerto, aquí está la máquina de devolución: web.archive.org/web/20160904162931/http://www.dotnet-tricks.com/…
majjam
201

La principal diferencia es que los operadores LINQ para IQueryable<T>tomar Expressionobjetos en lugar de delegados, lo que significa que la lógica de consulta personalizada que recibe, por ejemplo, un predicado o selector de valor, tiene la forma de un árbol de expresión en lugar de un delegado a un método.

  • IEnumerable<T> es ideal para trabajar con secuencias que se repiten en memoria, pero
  • IQueryable<T> permite cosas sin memoria como una fuente de datos remota, como una base de datos o un servicio web.

Consulta de ejecución:

  • Cuando la ejecución de una consulta se va a realizar "en proceso" , normalmente todo lo que se requiere es el código (como código) para ejecutar cada parte de la consulta.

  • Cuando la ejecución se realizará fuera del proceso , la lógica de la consulta debe representarse en datos de manera que el proveedor LINQ pueda convertirla en la forma adecuada para la ejecución sin memoria, ya sea una consulta LDAP, SQL o lo que sea.

Más en:

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

VonC
fuente
14
Me gusta la mención de operaciones sin memoria. Aclara una diferencia práctica real en el uso.
Ishmael Smyrnow
2
En lugar de tomar delegados como parámetros como el método IEnumerable <T> Donde lo hace, IQueryable <T> tomará los parámetros Expression <TDelegate>. No estamos pasando código a IQueryable <T>, estamos pasando árboles de expresión (código como datos) para que el proveedor LINQ los analice. C # 3.0 y LINQ
Lu55
Algo está sucediendo
jbooker
@joey Sin embargo, veo esa imagen muy bien en esta respuesta: i.stack.imgur.com/2DAqv.jpg
VonC
190

Este es un buen video en youtube que demuestra cómo difieren estas interfaces, vale la pena verlas.

A continuación hay una larga respuesta descriptiva para ello.

El primer punto importante a recordar es que la IQueryableinterfaz hereda IEnumerable, por lo que todo lo que IEnumerablepuede hacer, IQueryabletambién puede hacerlo.

ingrese la descripción de la imagen aquí

Hay muchas diferencias, pero discutamos sobre la gran diferencia que hace la mayor diferencia. IEnumerableLa interfaz es útil cuando su colección se carga con LINQEntity Framework y desea aplicar un filtro en la colección.

Considere el siguiente código simple que se usa IEnumerablecon el marco de la entidad. Está usando un Wherefiltro para obtener registros de quién EmpIdes 2.

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

Aquí donde el filtro se ejecuta en el lado del cliente donde está el IEnumerablecódigo. En otras palabras, todos los datos se obtienen a partir de la base de datos y luego en el cliente sus exploraciones y obtiene el registro con EmpIdes 2.

ingrese la descripción de la imagen aquí

Pero ahora ver el código de abajo hemos cambiado IEnumerablea IQueryable. Crea una consulta SQL en el lado del servidor y solo se envían los datos necesarios al lado del cliente.

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

ingrese la descripción de la imagen aquí

Entonces, la diferencia entre IQueryabley IEnumerablees sobre dónde se ejecuta la lógica del filtro. Uno se ejecuta en el lado del cliente y el otro se ejecuta en la base de datos.

Entonces, si trabaja solo con la recopilación de datos en memoria, IEnumerablees una buena opción, pero si desea consultar la recopilación de datos que está conectada con la base de datos, IQueryable es una mejor opción, ya que reduce el tráfico de red y utiliza el poder del lenguaje SQL.

Shivprasad Koirala
fuente
Hola, muchas gracias por la maravillosa explicación. Entiendo por qué IQueryable es una mejor opción para los datos "sin memoria", pero me cuesta entender por qué IEnumerable es mejor para los datos "en memoria". Todavía creo que es mejor obtener datos filtrados que obtener datos y aplicar filtros.
Imad
cuando está "en memoria" realmente no importa. los datos ya están en la memoria, no importa en qué momento exacto se filtre.
Roni Axelrad
@Imad Por ejemplo, proyectar datos mediante la conversión de la entidad DateTimeOffset a DateTime no se puede hacer con IQueryable o con EntityFunctions. La mejor manera es AsEnumerable () el objeto de entidad, luego Seleccionar () en un modelo de vista que contiene el DateTime. Este proceso utiliza funciones en memoria.
Jeff
57

IEnumerable: IEnumerable es el más adecuado para trabajar con la recopilación en memoria (o consultas locales). IEnumerable no se mueve entre elementos, solo se reenvía la colección.

IQueryable: IQueryable se adapta mejor a la fuente de datos remota, como una base de datos o servicio web (o consultas remotas). IQueryable es una característica muy poderosa que permite una variedad de escenarios de ejecución diferida interesantes (como paginación y consultas basadas en composición).

Entonces, cuando tiene que simplemente recorrer la colección en memoria, use IEnumerable, si necesita hacer alguna manipulación con la colección como Dataset y otras fuentes de datos, use IQueryable

Talha
fuente
3
¿IEnumerable no utiliza la ejecución diferida?
Ian Warburton
3
La ejecución diferida está disponible tanto en IEnumerable como en IQueryable. Puede encontrar más información interesante aquí: stackoverflow.com/questions/2876616/…
Ignacio Hagopian
18

En palabras simples, otra diferencia importante es que IEnumerable ejecuta la consulta de selección en el lado del servidor, carga los datos en la memoria en el lado del cliente y luego filtra los datos mientras IQueryable ejecuta la consulta de selección en el lado del servidor con todos los filtros.

A
fuente
17

En la vida real, si está utilizando un ORM como LINQ-to-SQL

  • Si crea un IQueryable, la consulta puede convertirse a sql y ejecutarse en el servidor de base de datos
  • Si crea un IEnumerable, todas las filas se extraerán en la memoria como objetos antes de ejecutar la consulta.

En ambos casos, si no se llama a una ToList()o ToArray()a continuación, la consulta será ejecutado cada vez que se utiliza, por lo que, por ejemplo, usted tiene una IQueryable<T>y llenar 4 cuadros de lista de él, entonces la consulta se ejecuta en la base de datos 4 veces.

Además, si extiende su consulta:

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

Luego, con un IQueryable, el SQL generado contendrá "where name =" a ", pero con un IEnumerable, muchos más roles serán retirados de la base de datos, luego .NET realizará la verificación x.name =" a ".

Ian Ringrose
fuente
10

IEnumerable se refiere a una colección, pero IQueryable es solo una consulta y se generará dentro de un árbol de expresiones. Ejecutaremos esta consulta para obtener datos de la base de datos.

seyed
fuente
8

La pequeña prueba mencionada a continuación puede ayudarlo a comprender un aspecto de la diferencia entre IQueryable<T>y IEnumerable<T>. He reproducido esta respuesta de esta publicación donde intentaba agregar correcciones a la publicación de otra persona

Creé la siguiente estructura en DB (secuencia de comandos DDL):

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

Aquí está el script de inserción de registro (script 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

Ahora, mi objetivo era simplemente obtener los 2 mejores registros de la Employeetabla en la base de datos. Agregué un elemento del modelo de datos de entidad ADO.NET en mi aplicación de consola que apunta a la Employeetabla en mi base de datos y comencé a escribir consultas LINQ.

Código para la ruta 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);
    }
}

Cuando comencé a ejecutar este programa, también comencé una sesión de SQL Query profiler en mi instancia de SQL Server y aquí está el resumen de ejecución:

  1. Número total de consultas realizadas: 1
  2. Consulta de texto: SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]

Es solo que IQueryablees lo suficientemente inteligente como para aplicar la Top (2)cláusula en el lado del servidor de la base de datos, por lo que solo trae 2 de 5 registros por cable. No se requiere ningún otro filtrado en memoria en el lado del equipo cliente.

Código para la ruta 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);
    }
}

Resumen de ejecución en este caso:

  1. Número total de consultas realizadas: 1
  2. Texto de consulta capturado en el generador de perfiles SQL: SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]

Ahora se IEnumerabletraen los 5 registros presentes en la Salarytabla y luego se realiza un filtrado en memoria en la computadora del cliente para obtener los 2 registros principales. Por lo tanto, se transfirieron innecesariamente más datos (3 registros adicionales en este caso) a través del cable.

RBT
fuente
7

Aquí está lo que escribí en una publicación similar (sobre este tema). (Y no, no suelo citarme, pero estos son artículos muy buenos).

"Este artículo es útil: IQueryable vs IEnumerable en LINQ-to-SQL .

Citando ese artículo, 'Según la documentación de MSDN, las llamadas realizadas en IQueryable funcionan mediante la construcción del árbol de expresión interno. "Estos métodos que extienden IQueryable (Of T) no realizan ninguna consulta directamente. En cambio, su funcionalidad es construir un objeto Expression, que es un árbol de expresión que representa la consulta acumulativa".

Los árboles de expresión son una construcción muy importante en C # y en la plataforma .NET. (Son importantes en general, pero C # los hace muy útiles). Para comprender mejor la diferencia, recomiendo leer sobre las diferencias entre expresiones y declaraciones en la especificación oficial de C # 5.0 aquí. Para conceptos teóricos avanzados que se ramifican en cálculo lambda, las expresiones permiten el soporte de métodos como objetos de primera clase. La diferencia entre IQueryable e IEnumerable se centra en este punto. IQueryable construye árboles de expresión, mientras que IEnumerable no, al menos no en términos generales para aquellos de nosotros que no trabajamos en los laboratorios secretos de Microsoft.

Aquí hay otro artículo muy útil que detalla las diferencias desde una perspectiva push vs pull. (Por "push" vs. "pull", me refiero a la dirección del flujo de datos. Técnicas de programación reactiva para .NET y C #

Aquí hay un muy buen artículo que detalla las diferencias entre la declaración lambdas y la expresión lambdas y discute los conceptos de expresión tress en mayor profundidad: Revisando delegados de C #, árboles de expresión y declaraciones lambda versus expresiones lambda. ".

devinbost
fuente
6

Utilizamos IEnumerabley IQueryablepara manipular los datos que se recuperan de la base de datos. IQueryablehereda de IEnumerable, por lo IQueryableque contiene todas las IEnumerablecaracterísticas. La principal diferencia entre IQueryabley IEnumerablees que IQueryableejecuta la consulta con filtros, mientras que IEnumerableprimero ejecuta la consulta y luego filtra los datos según las condiciones.

Encuentre una diferenciación más detallada a continuación:

IEnumerable

  1. IEnumerableexiste en el System.Collectionsespacio de nombres
  2. IEnumerable ejecutar una consulta de selección en el lado del servidor, cargar datos en la memoria en el lado del cliente y luego filtrar los datos
  3. IEnumerable es adecuado para consultar datos de colecciones en memoria como List, Array
  4. IEnumerable es beneficioso para LINQ to Object y LINQ to XML consultas

IQueryable

  1. IQueryableexiste en el System.Linqespacio de nombres
  2. IQueryable ejecuta una 'consulta de selección' en el lado del servidor con todos los filtros
  3. IQueryable es adecuado para consultar datos de colecciones de memoria insuficiente (como bases de datos remotas, servicios)
  4. IQueryable es beneficioso para consultas LINQ to SQL

Por IEnumerablelo tanto, generalmente se usa para lidiar con la recopilación en memoria, mientras que, en IQueryablegeneral , se utiliza para manipular colecciones.

VikrantMás
fuente
2

IQueryable es más rápido que IEnumerable si estamos tratando con grandes cantidades de datos de la base de datos porque, IQueryable solo obtiene los datos requeridos de la base de datos, mientras que IEnumerable obtiene todos los datos independientemente de la necesidad de la base de datos

Arjun Bollam
fuente
0

ienumerable: cuando queremos ocuparnos de la memoria en proceso, es decir, sin conexión de datos iqueryable: cuándo tratar con el servidor sql, es decir, con la conexión de datos ilist: operaciones como agregar objeto, eliminar objeto, etc.

viswanath n
fuente