linq to sql - ¿Debo devolver IEnumerable<T> o IQueryable<T> de mi DAL?
linq-to-sql datacontext (4)
Depende del comportamiento que desee.
- Devolver un IList <T> le dice a la persona que llama que recibió todos los datos que solicitó
- Devolver un IEnumerable <T> le dice a la persona que llama que tendrán que iterar sobre el resultado y que podría estar cargado de forma perezosa.
- La devolución de una IQueryable <T> le dice a la persona que llama que el resultado está respaldado por un proveedor de Linq que puede manejar ciertas clases de consultas, imponiendo la carga a la persona que llama para formar una consulta de rendimiento.
Si bien este último otorga a la persona que llama mucha flexibilidad (suponiendo que su repositorio lo soporte por completo), es el más difícil de probar y, posiblemente, el menos determinista.
Sé que esto podría ser opinión, pero estoy buscando las mejores prácticas.
Según tengo entendido, IQueryable<T>
implementa IEnumerable<T>
, por lo que en mi DAL, actualmente tengo firmas de métodos como las siguientes:
IEnumerable<Product> GetProducts();
IEnumerable<Product> GetProductsByCategory(int cateogoryId);
Product GetProduct(int productId);
¿Debo usar IQueryable<T>
aquí?
¿Cuáles son los pros y los contras de cualquiera de los enfoques?
Tenga en cuenta que estoy planeando usar el patrón Repositorio, así que tendré una clase como esta:
public class ProductRepository {
DBDataContext db = new DBDataContext(<!-- connection string -->);
public IEnumerable<Product> GetProductsNew(int daysOld) {
return db.GetProducts()
.Where(p => p.AddedDateTime > DateTime.Now.AddDays(-daysOld ));
}
}
¿Debo cambiar mi IEnumerable<T>
a IQueryable<T>
? ¿Qué ventajas / desventajas hay para uno u otro?
Diferencia HUUUUGGGE. Veo esto bastante.
Usted crea un IQueryable antes de que llegue a la base de datos. IQueryable solo llega al DB una vez que se llama una función ansiosa (.ToList () por ejemplo) o si realmente intenta extraer valores. IQueryable = flojo.
Un IEnumerable ejecutará su lambda contra el DB de inmediato. IEnumerable = ansioso.
En cuanto a qué usar con el patrón Repository, creo que está ansioso. Por lo general, veo que se pasan ILists, pero alguien más tendrá que resolver eso por ti. EDITAR - Usualmente ves IEnumerable en lugar de IQueryable porque no quieres que las capas pasen de tu Repository A) a determinar cuándo sucederá la base de datos o B) Agregar lógica a las combinaciones fuera del Repository
Hay un muy buen video de LINQ que disfruto mucho, no solo IEnumerable v IQueryable, sino que realmente tiene una visión fantástica.
http://channel9.msdn.com/posts/matthijs/LINQ-Tips-Tricks-and-Optimizations-by-Scott-Allen/
Puede usar IQueryable y aceptar que alguien podría crear un escenario donde podría suceder SELECT N + 1 . Esto es una desventaja, junto con el hecho de que puede terminar con un código que es específico para la implementación de su repositorio en las capas superiores a su repositorio. La ventaja de esto es que permite que las operaciones comunes de delegación, como la búsqueda y la clasificación, se expresen fuera de su repositorio, lo que lo alivia de tales preocupaciones. También es más flexible si necesita unir los datos con otras tablas de la base de datos, ya que la consulta seguirá siendo una expresión, por lo que puede agregarse antes de que se resuelva en una consulta y llegue a la base de datos.
La alternativa es bloquear su repositorio para que devuelva listas materializadas llamando a ToList()
. Con el ejemplo de paginación y clasificación, deberá pasar skip, take y una expresión de ordenación como parámetros a los métodos de su repositorio, y usar los parámetros para devolver solo una ventana de resultados. Esto significa que el repositorio asume la responsabilidad de buscar y clasificar, y toda la proyección de sus datos.
Esto es un poco crítico, le da a su aplicación el poder de linq, y tiene menos complejidad en el repositorio, o controla su acceso a los datos. Para mí, depende del número de consultas asociadas con cada entidad y de las combinaciones de entidades, y de dónde quiero gestionar esa complejidad.
Una cosa más para pensar: ¿dónde está tu soporte de paginación / clasificación? Si proporciona soporte de paginación dentro de su repositorio, devolver IEnumerable<T>
está bien. Si está buscando fuera de su repositorio (como en el controlador o la capa de servicio), entonces realmente desea utilizar IQueryable<T>
porque no desea cargar todo el conjunto de datos en la memoria antes de que se lo pagine.