¿De qué sirve IQueryable
en el contexto de LINQ?
¿Se utiliza para desarrollar métodos de extensión o para cualquier otro propósito?
fuente
¿De qué sirve IQueryable
en el contexto de LINQ?
¿Se utiliza para desarrollar métodos de extensión o para cualquier otro propósito?
La respuesta de Marc Gravell es muy completa, pero también pensé en agregar algo sobre esto desde el punto de vista del usuario ...
La principal diferencia, desde la perspectiva del usuario, es que, cuando usa IQueryable<T>
(con un proveedor que admite las cosas correctamente), puede ahorrar muchos recursos.
Por ejemplo, si está trabajando en una base de datos remota, con muchos sistemas ORM, tiene la opción de obtener datos de una tabla de dos maneras, una que devuelve IEnumerable<T>
y otra que devuelve un IQueryable<T>
. Digamos, por ejemplo, que tiene una tabla de Productos y desea obtener todos los productos cuyo costo es> $ 25.
Si lo haces:
IEnumerable<Product> products = myORM.GetProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
Lo que sucede aquí es que la base de datos carga todos los productos y los pasa a través del cable a su programa. Su programa luego filtra los datos. En esencia, la base de datos hace un SELECT * FROM Products
, y le devuelve CADA producto.
Con el IQueryable<T>
proveedor adecuado , por otro lado, puede hacer:
IQueryable<Product> products = myORM.GetQueryableProducts();
var productsOver25 = products.Where(p => p.Cost >= 25.00);
El código se ve igual, pero la diferencia aquí es que el SQL ejecutado lo será SELECT * FROM Products WHERE Cost >= 25
.
Desde su POV como desarrollador, esto se ve igual. Sin embargo, desde el punto de vista del rendimiento, solo puede devolver 2 registros a través de la red en lugar de 20,000 ...
IQueryable<Product>
- sería específico para su ORM o repositorio, etc.foreach
o llameToList()
), en realidad no golpea la base de datos.En esencia, su trabajo es muy similar a
IEnumerable<T>
- para representar una fuente de datos consultable - la diferencia es que los diversos métodos LINQ (onQueryable
) pueden ser más específicos, para construir la consulta usandoExpression
árboles en lugar de delegados (que es lo queEnumerable
usa).El proveedor LINQ elegido puede inspeccionar los árboles de expresión y convertirlos en un consulta real , aunque eso es un arte negro en sí mismo.
Esto realmente depende de
ElementType
,Expression
yProvider
- pero en realidad rara vez necesita preocuparse por esto como usuario . Solo un implementador de LINQ necesita conocer los detalles sangrientos.Re comentarios; No estoy muy seguro de lo que quiere a modo de ejemplo, pero considere LINQ-to-SQL; El objeto central aquí es un
DataContext
, que representa nuestro contenedor de base de datos. Esto normalmente tiene una propiedad por tabla (por ejemplo,Customers
) y una tabla se implementaIQueryable<Customer>
. Pero no usamos mucho directamente; considerar:esto se convierte (por el compilador de C #):
que nuevamente es interpretado (por el compilador de C #) como:
Es importante destacar que los métodos estáticos en
Queryable
árboles de expresión de toma, que, en lugar de IL normal, se compilan en un modelo de objetos. Por ejemplo, solo mirando el "Dónde", esto nos da algo comparable a:¿El compilador no hizo mucho por nosotros? Este modelo de objetos se puede desgarrar, inspeccionar para ver qué significa y volver a armar mediante el generador TSQL, dando algo como:
(la cadena podría terminar como un parámetro; no recuerdo)
Nada de esto sería posible si acabáramos de usar un delegado. Y este es el punto de
Queryable
/IQueryable<T>
: proporciona el punto de entrada para usar árboles de expresión.Todo esto es muy complejo, por lo que es un buen trabajo que el compilador lo haga agradable y fácil para nosotros.
Para obtener más información, consulte " C # en profundidad " o " LINQ en acción ", que proporcionan cobertura de estos temas.
fuente
Aunque Reed Copsey y Marc Gravell ya describieron sobre
IQueryable
(y tambiénIEnumerable
) lo suficiente, quiero agregar un poco más aquí al proporcionar un pequeño ejemploIQueryable
yIEnumerable
tantos usuarios lo pidieronEjemplo : he creado dos tablas en la base de datos
La clave primaria (
PersonId
) de la tablaEmployee
también es una clave forgein (personid
) de la tablaPerson
A continuación, agregué el modelo de entidad ado.net en mi aplicación y creo la clase de servicio a continuación en ese
Contienen el mismo linq. Invocó
program.cs
como se define a continuaciónLa salida es la misma para ambos obviamente
Entonces, la pregunta es ¿cuál / dónde está la diferencia? No parece tener ninguna diferencia ¿verdad? ¡¡De Verdad!!
Echemos un vistazo a las consultas sql generadas y ejecutadas por la entidad framwork 5 durante este período
Parte de ejecución IQueryable
I Parte de ejecución numerable
Script común para ambas partes de ejecución
Entonces tienes algunas preguntas ahora, déjame adivinarlas y tratar de responderlas
¿Por qué se generan diferentes scripts para el mismo resultado?
Veamos algunos puntos aquí,
todas las consultas tienen una parte común
WHERE [Extent1].[PersonId] IN (0,1,2,3)
¿por qué? Porque tanto function
IQueryable<Employee> GetEmployeeAndPersonDetailIQueryable
comoIEnumerable<Employee> GetEmployeeAndPersonDetailIEnumerable
ofSomeServiceClass
contienen una línea común en consultas linqwhere employeesToCollect.Contains(e.PersonId)
Entonces, ¿por qué
AND (N'M' = [Extent1].[Gender])
falta la parte en laIEnumerable
parte de ejecución, mientras que en ambas llamadas a funciones usamosWhere(i => i.Gender == "M") in
program.cs`¿Qué entidad hace el marco cuando un
IQueryable
se llama a método, toma la instrucción linq escrita dentro del método e intenta averiguar si se definen más expresiones linq en el conjunto de resultados, luego reúne todas las consultas linq definidas hasta que el resultado necesita buscar y construir sql más apropiado consulta a ejecutar.Proporciona muchos beneficios como,
como aquí en el ejemplo, el servidor sql regresó a la aplicación solo dos filas después de la ejecución IQueryable` pero devolvió TRES filas para la consulta IEnumerable ¿por qué?
En el caso del
IEnumerable
método, el marco de la entidad tomó la declaración linq escrita dentro del método y construye la consulta sql cuando el resultado necesita ser recuperado. no incluye la parte rest linq para construir la consulta sql. Al igual que aquí, no se realiza ningún filtrado en el servidor SQL en la columnagender
.Pero las salidas son las mismas? Porque 'IEnumerable filtra el resultado aún más en el nivel de aplicación después de recuperar el resultado del servidor SQL
Entonces, ¿qué debería elegir alguien? Personalmente, prefiero definir el resultado de la función
IQueryable<T>
porque , debido a que tiene muchos beneficiosIEnumerable
, podría unir dos o más funciones IQueryable, que generan un script más específico para el servidor SQL.Aquí, por ejemplo, puede ver y
IQueryable Query(IQueryableQuery2)
genera un script más específico que elIEnumerable query(IEnumerableQuery2)
que es mucho más aceptable en mi punto de vista.fuente
Permite realizar más consultas más adelante. Si esto fuera más allá de un límite de servicio, entonces, el usuario de este objeto IQueryable podría hacer más con él.
Por ejemplo, si estaba usando carga diferida con nhibernate, esto podría provocar que el gráfico se cargue cuando sea necesario.
fuente