.net - example - ¿Cuál es la diferencia entre IQueryable<T> y IEnumerable<T>?
iqueryable example c# (12)
¿Cuál es la diferencia entre IQueryable<T>
y IEnumerable<T>
?
Vea también ¿Cuál es la diferencia entre IQueryable e IEnumerable que se superpone con esta pregunta?
A continuación, la pequeña prueba mencionada podría ayudarlo a comprender un aspecto de la diferencia entre IQueryable<T>
e IEnumerable<T>
. He reproducido esta respuesta de this publicación en la que intentaba agregar correcciones a la publicación de otra persona.
Creé la siguiente estructura en DB (script 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 dos primeros registros de la tabla de Employee
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 tabla de Employee
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 inicié una sesión del analizador de SQL Query en mi instancia de SQL Server y aquí está el resumen de ejecución:
- Número total de consultas realizadas: 1
- Texto de consulta:
SELECT TOP (2) [c].[Salary] AS [Salary] FROM [dbo].[Employee] AS [c]
Es solo que IQueryable
es lo suficientemente inteligente como para aplicar la cláusula Top (2)
en el lado del servidor de la base de datos, por lo que solo trae 2 de 5 registros a través del cable. Cualquier otro filtrado en memoria no se requiere en absoluto en el lado de la computadora cliente.
Código para la ruta de 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:
- Número total de consultas realizadas: 1
- Texto de consulta capturado en el analizador de SQL:
SELECT [Extent1].[Salary] AS [Salary] FROM [dbo].[Employee] AS [Extent1]
Ahora la cosa es que IEnumerable
trajo todos los 5 registros presentes en la tabla de Salary
y luego realizó un filtrado en memoria en la computadora cliente para obtener los 2 mejores registros. Así que más datos (3 registros adicionales en este caso) se transfirieron por el cable innecesariamente.
En la vida real, si está utilizando un ORM como LINQ-to-SQL
- Si crea un IQueryable, entonces la consulta puede convertirse a sql y ejecutarse en el servidor de base de datos
- Si crea un IEnumerable, todas las filas se arrastrarán a la memoria como objetos antes de ejecutar la consulta.
En ambos casos, si no llama a ToList()
o ToArray()
, la consulta se ejecutará cada vez que se use, por lo que, digamos, tiene un IQueryable<T>
y llena de ella 4 cuadros de lista, luego el La consulta se ejecutará contra la base de datos 4 veces.
También si amplías tu consulta:
q.Where(x.name = "a").ToList()
Luego, con un IQueryable, el SQL generado contendrá "donde nombre =" a ", pero con un IEnumerable, muchos más roles se retirarán de la base de datos, luego la verificación x.name =" a "se realizará por .NET.
En palabras sencillas, otra gran diferencia 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.
En primer lugar, IQueryable<T>
amplía la IEnumerable<T>
, por lo que cualquier cosa que pueda hacer con un IEnumerable<T>
" IEnumerable<T>
" IEnumerable<T>
, también puede hacerlo con un IQueryable<T>
.
IEnumerable<T>
solo tiene un método GetEnumerator()
que devuelve un Enumerator<T>
para el cual puede llamar a su método MoveNext()
para iterar a través de una secuencia de T.
Lo que IQueryable<T>
tiene que IEnumerable<T>
no son dos propiedades en particular, una que apunta a un proveedor de consultas (por ejemplo, un proveedor de 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 atravesar en tiempo de ejecución que puede ser comprendido por el proveedor de consultas dado (en su mayor parte, no puede otorgar una expresión de LINQ a SQL a un proveedor de LINQ a entidades sin que se lance 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. Los IQueryProvider.Execute()
o IQueryProvider.CreateQuery()
del proveedor de consultas se llaman con una expresión que se le pasa, y luego se devuelve un resultado de la consulta u otro IQueryable
, respectivamente.
Este es un buen video en mi página de Facebook que demuestra cómo estas interfaces difieren, vale la pena verlas.
A continuación va una larga respuesta descriptiva para ello.
El primer punto importante a recordar es que la interfaz IEnumerable
hereda de IEnumerable
, por lo que cualquier IEnumerable
que IQueryable
pueda hacer, IQueryable
también lo puede hacer.
Hay muchas diferencias, pero discutamos sobre la gran diferencia que hace la mayor diferencia. IEnumerable
interfaz IEnumerable
es útil cuando su colección se carga con LINQ
o Entity framework y desea aplicar un filtro en la colección.
Considere el siguiente código simple que usa IEnumerable
con el marco de la entidad. Está utilizando un filtro Where
para obtener registros cuyo EmpId
es 2
.
EmpEntities ent = new EmpEntities();
IEnumerable<Employee> emp = ent.Employees;
IEnumerable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
Esto donde el filtro se ejecuta en el lado del cliente donde está el código IEnumerable
. En otras palabras, todos los datos se obtienen de la base de datos y luego, en el cliente, los escaneos y el registro con EmpId
es 2
.
Pero ahora vea el siguiente código que hemos cambiado IQueryable
a IEnumerable
. Crea una consulta SQL en el lado del servidor y solo los datos necesarios se envían al lado del cliente.
EmpEntities ent = new EmpEntities();
IQueryable<Employee> emp = ent.Employees;
IQueryable<Employee> temp = emp.Where(x => x.Empid == 2).ToList<Employee>();
Por lo tanto, la diferencia entre IEnumerable
e IQueryable
es sobre dónde se ejecuta la lógica de filtro. Uno se ejecuta en el lado del cliente y el otro se ejecuta en la base de datos.
Por lo tanto, si trabaja solo con la recopilación de datos en memoria, IEnumerable
es una buena opción, pero si desea consultar la recopilación de datos relacionada con la base de datos, IQueryable es una mejor opción, ya que reduce el tráfico de red y utiliza la potencia del lenguaje SQL.
Esto es 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, ''De acuerdo con la documentación de MSDN, las llamadas realizadas en IQueryable funcionan al construir el árbol de expresiones internas en su lugar. "Estos métodos que extienden IQueryable (Of T) no realizan ninguna consulta directamente. En cambio, su funcionalidad es crear un objeto de expresión, 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 entender mejor la diferencia, recomiendo leer sobre las diferencias entre expresiones y declaraciones en la especificación oficial de C # 5.0 aquí. Para los conceptos teóricos avanzados que se ramifican en el 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 lo hace, 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 de empujar contra tirar. (Por "empujar" contra "tirar", 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 las sentencias lambda y expresión lambdas y discute los conceptos de la expresión con mayor profundidad: revisando los delegados de C #, los árboles de expresión y las declaraciones lambda frente a las expresiones lambda . "
IEnumerable hace referencia 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.
IQueryable es más rápido que IEnumerable si estamos tratando con grandes cantidades de datos de la base de datos, ya que IQueryable solo obtiene los datos requeridos de la base de datos donde IEnumerable obtiene todos los datos independientemente de la necesidad de la base de datos.
La diferencia principal es que los operadores LINQ para IQueryable<T>
toman objetos de Expression
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 iteran en memoria, pero -
IQueryable<T>
permite cosas fuera de la memoria, como un origen de datos remoto, como una base de datos o un servicio web.
Ejecución de la consulta:
Cuando la ejecución de una consulta se realizará "en proceso" , normalmente todo lo que se requiere es el código (como código) para ejecutar cada parte de la consulta.
Donde la ejecución se llevará a cabo fuera del proceso , la lógica de la consulta debe representarse en datos tales que el proveedor LINQ pueda convertirla en la forma adecuada para la ejecución fuera de la memoria, ya sea una consulta LDAP. SQL o lo que sea.
Más en:
- LINQ:
IEnumerable<T>
eIQueryable<T>
- C # 3.0 y LINQ .
- " Devolviendo
IEnumerable<T>
vsIQueryable<T>
" - Programación reactiva para desarrolladores .NET y C #: una introducción a
IQueryable
,IObservable
,IQbservable
eIQbservable
Tanto IEnumerable como IQueryable se utilizan para mantener la recopilación de datos y realizar operaciones de manipulación de datos, por ejemplo, filtrando la recopilación de datos. Aquí puedes encontrar la mejor comparación de diferencias con el ejemplo. http://www.gurujipoint.com/2017/05/difference-between-ienumerable-and.html
ienumerable: cuando queremos lidiar con la memoria en proceso, es decir, sin conexión de datos iqueryable: cuándo tratar con el servidor SQL, es decir, con ilist de conexión de datos: operaciones como agregar objeto, eliminar objeto, etc.
IEnumerable: IEnumerable es el más adecuado para trabajar con recopilaciones en memoria (o consultas locales). IEnumerable no se mueve entre los elementos, es solo la colección hacia adelante.
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 interesantes escenarios de ejecución diferida (como consultas basadas en paginación y composición).
Entonces, cuando tenga que recorrer la colección en memoria, use IEnumerable, si necesita realizar alguna manipulación con la colección como Dataset y otras fuentes de datos, use IQueryable