net mvc español asp asp.net-mvc model-view-controller controller business-logic

asp.net-mvc - español - asp.net core 2 mvc



¿Es una buena práctica tener consulta de linq en Controladores? (2)

No estoy muy familiarizado con el patrón MVC. ¿Podría decirme cuál de las siguientes tres acciones de controlador es mejor? Gracias :)

(1) Tener consulta en acción:

public ActionResult List() { var query = repository.Query().Where(it => it.IsHandled).OrderBy(it => it.Id); // ... }

(2) Tener consulta en servicio:

public ActionResult List() { var items = service.GetHandledItemsOrderById(); // ... }

(3) Tener orden por en acción:

public ActionResult List() { var items = service.GetHandledItems().OrderBy(it => it.Id); // ... }

Si elegimos (1), entonces tenemos demasiada lógica comercial en el controlador?

Si elegimos (2), puede haber muchos métodos de servicio como GetXXXByYYY() .

Si elegimos (3), por qué encapsulamos Where(it => it.IsHandled) pero no
OrderBy(it => it.Id

¿Algunas ideas?


Estoy seguro de que las opiniones pueden variar, pero he aprendido a tratar de mantener la mayor lógica de negocios en el servicio como sea posible. 3 sería mi elección. Con 1, ya has detectado el problema. Con 2, está introduciendo prioridad de visualización en un servicio. Con 3, maneja las preferencias de visualización donde sea necesario. Si tuviera que introducir otra interfaz en su capa de negocio, está requiriendo iteraciones de código potencialmente innecesarias al elegir 2.


Depende. :)

Mi opinión:

Me gusta mantener mi servicio suelto, para minimizar el código duplicado. También soy fanático de las tuberías y los filtros.

Esto es lo que haría (y HAGO).

Servicio

public ICollection<Item> GetHandledItems<TKey>(OrderingOptions<Item, TKey> orderingOptions) { return repository .Query() .WhereHandled() .WithOrdering(orderingOptions) .ToList(); }

ItemFilters.cs

public static IQueryable<Item> WhereHandled(this IQueryable<Item> source) { return source.Where(it => it.IsHandled); } public static IOrderedQueryable<T> WithOrdering<T, TKey>( this IQueryable<T> source, OrderingOptions<T, TKey> orderingOptions) { return orderingOptions.SortDescending ? source.OrderByDescending(orderingOptions.OrderingKey) : source.OrderBy(orderingOptions.OrderingKey); }

OrderingOptions.cs

public class OrderingOptions<T,TKey> { public OrderingOptions(Expression<Func<T,TKey>> orderingKey, bool sortDescending = false) { OrderingKey = orderingKey; SortDescending = sortDescending; } public Expression<Func<T,TKey>> OrderingKey { get; private set; } public bool SortDescending { get; private set; } }

De esta forma, puede especificar el orden en el Controlador:

var items = service.GetHandledItems(new OrderingOptions(it => it.Id));

Diferencias entre lo anterior y las opciones 3:

  • Arriba materializa la secuencia antes de regresar al controlador. La opción 3 no lo hace, lo cual es peligroso (podría terminar devolviendo la consulta a Ver y romper el patrón MVC).
  • POCO genérico "Pedido" se puede usar en cualquier lugar y mantiene sus consultas SECAS.
  • El servicio se vuelve tonto , y simplemente un mitigador entre el repositorio y el controlador (que es todo lo que debe hacer, IMO). Lógica (por ejemplo, filtros) abstraída a un lugar.

HTH