6

Estoy usando ASP.NET MVC 3. Puedo obtener los datos de mi vista en la siguiente secuencia:¿El filtrado de datos tiene lugar en las capas de controlador, servicio o repositorio?

Controller -> Service Layer -> Repository 

En mi repositorio que tienen un método GetAll que recupera todos los registros de un objeto específico, como Categoría.

Así que si necesito una lista de todos las categorías a continuación, en mi controlador Me gustaría tener algo como:

IEnumerable<Category> categories = categoryService.GetAll(); 

En la capa de servicio que tendría algo como:

public IEnumerable<Category> GetAll() 
{ 
    return categoryRepository.GetAll(); 
} 

Ahora esto es lo que necesito saber ¿dónde realmente empiezo a filtrar los datos? ¿Se puede hacer en cualquier lugar en una de estas 3 capas o solo tiene que estar en la capa de repositorio? Digamos que necesito todas las categorías principales. ¿Tengo el .GetAll.Where(x => x.ParentCategoryId == null); en mi controlador, capa de servicio o capa de repositorio?

¿Debo tenerlo como este en mi controlador:

IEnumerable<Category> categories = categoryService.GetParentCategories(); 

Y en mi capa de servicio que puede tener:

public IEnumerable<Category> GetParentCategories() 
{ 
    return categoryRepository.GetAll.Where(x => x.ParentCategoryId == null); 
} 

O es que mi capa de servicio tiene que tener este aspecto:

public IEnumerable<Category> GetParentCategories() 
{ 
    return categoryRepository.GetParentCategories(); 
} 

Y luego en mi capa de repositorio de esta manera:

public IEnumerable<Category> GetParentCategories() 
{ 
    return GetAll() 
      .Where(x => x.ParentCategoryId == null); 
} 

Por favor alguien puede ayudar a aclarar esta confusión que tengo. Puede haber diferentes escenarios. Podría traer de vuelta todas las categorías que tienen un estado activo. Podría traer de vuelta categorías con un estado inactivo. Entonces, ¿necesito un método para cada uno?

Respuesta

4

Debe filtrar lo más cerca posible del origen de datos, de lo contrario estará recuperando registros en capas superiores que simplemente se descartarán debido a una opción de filtrado. Esto no se escala bien, por lo que debe exponer las capacidades de filtrado en todas las capas que lo requieren, pero asegúrese de que el filtrado real se realice en la capa más baja posible, generalmente se realiza en el nivel de la base de datos.

En el ejemplo que publicó si usa GetAll que devuelve IEnumerable de todos los registros y solo luego aplica el filtrado, tendrá problemas en el futuro porque básicamente está cargando una tabla completa en la memoria y solo luego aplicando un filtración.

Dado que está utilizando EF, puede aprovechar las propiedades de ejecución diferida del IQueryable.Compruebe:

.NET Entity Framework - IEnumerable VS. IQueryable

Should a Repository return IEnumerable , IQueryable or List?


Actualización: Siguiendo con su comentario También debe comprobar:

LINQ to entities vs LINQ to objects - Are they the same?

+0

GetAll es solo un método de muestra, el foco principal está en la parte de filtrado. ¿Entonces creo un método en el repositorio para cada uso? Pero, ¿no funciona el .Where (...) como un sql select con una cláusula where? –

+0

Solo cuando uses LINQ para entidades y necesitarás 'IQueryable' para eso. –

+0

Sí. Tengo un método Get tat es IQueryable en el repositorio, por lo que el repositorio puede manejar todas las condiciones que se le presenten. Un método GetALlUsers() me hace despedir gente. Es ineficiente como el infierno. Atrayendo a 100.9000 usuarios para obtener uno por nombre - no. – TomTom

2

Usted siempre debe tratar de alcanzar un precio de poco como sea posible desde la base de datos. Y por lo tanto, debe hacer todos los filtros en sus clases de repositorio.

Muchos artículos sugieren que cree y use repositorios genéricos. Pero no funcionarán muy bien cuando su aplicación crezca. Le recomiendo que crear clases de repositorios apropiados con métodos de búsqueda adecuadas como:

emailRepository.GetForUser("Ada"); 
userRepository.GetNewUsers(); 

En primer lugar, se oculta los detalles de implementación como la forma de identificar a los nuevos usuarios. También hace que el código sea más fácil de comprender y extender que utilizar una consulta genérica.

También puede añadir algunas opciones de filtrado:

emailRepository.GetForUser("Ada", Filtering.New().Paged(1, 20).SortedBy("FirstName")); 

A diferencia @ JoãoAngelo no recomiendo que utilice IQueryable fuera de su repositorio. Al hacerlo, moverá la ejecución de la base de datos a fuera de su clase de repositorio. Y eso significa que cualquier error no puede ser manejado por su repositorio.

Cuestiones relacionadas