ejemplos - linq c# custom
Para devolver IQueryable<T> o no devolver IQueryable<T> (3)
Tengo una clase de repositorio que envuelve mi LINQ al contexto de datos de SQL. La clase de repositorio es una clase de línea de negocio que contiene toda la lógica de nivel de datos (y almacenamiento en caché, etc.).
Aquí está mi v1 de mi interfaz repo.
public interface ILocationRepository
{
IList<Location> FindAll();
IList<Location> FindForState(State state);
IList<Location> FindForPostCode(string postCode);
}
Pero para gestionar la búsqueda de FindAll, estoy debatiendo si exponer IQueryable <ILocation> en lugar de IList para simplificar la interfaz en circunstancias como la búsqueda.
¿Cuáles son los pros y los contras de exponer IQueryable del repositorio de datos?
Cualquier ayuda es muy apreciada.
Los profesionales; capacidad de compilación:
- las personas que llaman pueden agregar filtros
- los llamantes pueden agregar paginación
- los llamantes pueden agregar clasificación
- etc
Los contras; no-comprobabilidad:
- Su repositorio ya no es adecuadamente verificable por unidad; no puedes confiar en a: funciona, b: lo que hace;
- el llamante podría agregar una función no traducible (es decir, sin mapeo TSQL; interrupciones en el tiempo de ejecución)
- la persona que llama podría agregar un filtro / clasificación que lo haga funcionar como un perro
- Como las personas que llaman esperan que
IQueryable<T>
sea composable, descarta las implementaciones que no se pueden componer, o le obliga a escribir su propio proveedor de consultas para ellas. - significa que no puede optimizar / perfilar el DAL
Para mayor estabilidad, he IQueryable<T>
no exponer IQueryable<T>
o Expression<...>
en mis repositorios. Esto significa que sé cómo se comporta el repositorio, y mis capas superiores pueden usar simulaciones sin preocuparse "¿el repositorio real respalda esto?" (forzando pruebas de integración).
Todavía uso IQueryable<T>
etc. dentro del repositorio, pero no sobre el límite. Publiqué algunas reflexiones más sobre este tema aquí . Es tan fácil poner los parámetros de paginación en la interfaz del repositorio. Incluso puede usar métodos de extensión (en la interfaz) para agregar parámetros de paginación opcionales , de modo que las clases concretas solo tengan 1 método para implementar, pero puede haber 2 o 3 sobrecargas disponibles para la persona que llama.
Recomiendo usar IEnumerable
lugar de IList
, con él tendrá más flexibilidad.
De esta forma, solo podrá obtener de Db esa porción de datos que realmente va a utilizar sin realizar un trabajo adicional en su repositorio.
Muestra:
// Repository
public interface IRepository
{
IEnumerable<Location> GetLocations();
}
// Controller
public ActionResult Locations(int? page)
{
return View(repository.GetLocations().AsPagination(page ?? 1, 10);
}
Que es súper limpio y simple.
Como se mencionó en la respuesta anterior, exponer IQueryable da acceso a las personas que llaman para jugar con IQueryable, que es o puede ser peligroso.
La primera responsabilidad de la lógica de negocios encapsulante es mantener la integridad de su base de datos.
Puede continuar exponiendo IList y puede cambiar sus parámetros de la siguiente manera, así es como lo estamos haciendo ...
public interface ILocationRepository
{
IList<Location> FindAll(int start, int size);
IList<Location> FindForState(State state, int start, int size);
IList<Location> FindForPostCode(string postCode, int start, int size);
}
si size == -1 luego devuelve todo ...
Forma alternativa...
Si aún desea devolver IQueryable, puede devolver IQueryable of List dentro de sus funciones ... por ejemplo ...
public class MyRepository
{
IQueryable<Location> FindAll()
{
List<Location> myLocations = ....;
return myLocations.AsQueryable<Location>;
// here Query can only be applied on this
// subset, not directly to the database
}
}
El primer método tiene una ventaja sobre la memoria, porque devolverá menos datos en lugar de todos.