11

Non ho molta familiarità con il pattern MVC. Potresti dirmi quale delle seguenti tre azioni del controller è migliore? Grazie :)È buona norma avere una query linq in Controller?

(1) Avere query in azione:

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

(2) Avere query in servizio:

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

(3) avere ordine per in azione :

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

Se scegliamo (1), abbiamo troppa logica di business nel controller?

Se scegliamo (2), potrebbero esserci molti metodi di servizio come GetXXXByYYY().

Se scegliamo (3), perché incapsuliamo Where(it => it.IsHandled) ma non
OrderBy(it => it.Id.

Qualche idea?

risposta

3

Dipende. :)

La mia opinione:

mi piace tenere il mio servizio sciolto, per ridurre al minimo il codice duplicato. Sono anche un fan di pipe e filtri.

Ecco cosa farei (e FARE).

Servizio

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; } 
} 

questo modo, yo u possibile specificare l'ordine nel controller:

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

Differenze tra il sopra e opzioni 3:

  • Sopra materializza sequenza prima di tornare al controller. L'opzione 3 non lo è, il che è pericoloso (si potrebbe finire per restituire la query a Visualizza e interrompe il pattern MVC).
  • POCO "Ordine" generico, può essere utilizzato ovunque e mantiene le vostre domande D-R-Y.
  • Il servizio diventa stupido e semplicemente un mitigatore tra il repository e il controller (che è tutto ciò che dovrebbe fare, IMO). Logica (ad esempio filtri) astratta in un unico luogo.

HTH

+0

Grazie. Bu se "GetHandledItems()" restituisce una raccolta (non IQueryable), non è possibile eseguire proiezioni sulla query. Influirà sulle prestazioni. –

+0

@Dylan - Quindi le tue proiezioni nel servizio prima di eseguire la query, inline o tramite un altro metodo pipe, ad es .: 'return repo.Query(). WhereHandled(). WithOrdering(). AsSomeProjectedType()' – RPM1984

+0

Guarda anche questo ** geniale ** RobCon vid su MVC Pipes & Filters: http://www.asp.net/mvc/videos/aspnet-mvc-storefront-part-3-pipes-and-filters – RPM1984

4

Sono sicuro che le opinioni possono variare, ma ho imparato a cercare di mantenere il più possibile la logica di business nel servizio. 3 sarebbe la mia scelta. Con 1, hai già individuato il problema. Con 2, si introduce la precedenza sulla visualizzazione in un servizio. Con 3, gestisci le preferenze di visualizzazione dove necessario. Se dovessi introdurre un'altra interfaccia per il tuo livello aziendale, stai richiedendo potenzialmente, inutili iterazioni di codice scegliendo 2.

+0

La pagina ha la necessità di visualizzare gli elementi che sono gestiti da ordine Id. Perché "visualizzare articoli già elaborati (elaborati)" è una logica aziendale e dovrebbe essere in servizio, mentre "visualizza gli elementi ordinati per ID" è la preferenza di visualizzazione? –

+0

Penso che "display handled items" e "display items order by id" siano entrambi preferenze di visualizzazione? Quindi dovremmo scegliere 1? –

+1

Penso che la mia domanda dovrebbe essere: (1) La logica di business "Where (it => it.IsHandled)"? (2) La logica di business "OrderBy (it => it.Id)"? –