6

Sto usando ASP.NET MVC 3. I ottenere i dati del mio modo di vedere nel seguente ordine:Il filtraggio dei dati avviene nei livelli controller, servizio o repository?

Controller -> Service Layer -> Repository 

Nel mio repository Ho un metodo GetAll che riporta tutti i record per un oggetto specifico, come categoria.

Quindi, se ho bisogno di un elenco di tutte le categorie poi nel mio controller vorrei avere qualcosa di simile:

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

Nel livello di servizio vorrei avere qualcosa di simile:

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

Ora questo è quello che devo sapere da dove effettivamente inizio a filtrare i dati? Può essere fatto ovunque in uno di questi 3 livelli o deve essere solo nel livello repository? Diciamo che ho bisogno di tutte le categorie genitore. Ho il .GetAll.Where(x => x.ParentCategoryId == null); nel mio controller, livello di servizio o livello di repository?

ce l'ho come questo nel mio controller:

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

E nel mio livello di servizio che può avere:

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

O fa il mio livello di servizio deve guardare in questo modo:

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

E quindi nel mio livello di repository in questo modo:

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

Per favore qualcuno può aiutare a chiarire questa confusione che ho. Potrebbero esserci diversi scenari. Potrei riportare tutte le categorie che hanno uno stato attivo. Potrei riportare le categorie con uno stato inattivo. Allora ho bisogno di un metodo per ciascuno?

risposta

4

Si dovrebbe filtrare il più vicino possibile dall'origine dati, altrimenti si recupereranno i record ai livelli superiori che verranno semplicemente scartati a causa di un'opzione di filtro. Questo non si adatta bene, quindi è necessario esporre le funzionalità di filtraggio a tutti i livelli che lo richiedono, ma assicurarsi che il filtro effettivo sia eseguito nel livello più basso possibile, generalmente viene eseguito a livello di database.

Nell'esempio che hai postato se usiche restituisce un IEnumerable di tutti i record e solo dopo applichi il filtro avrai problemi in futuro perché in pratica stai caricando un intero tavolo in memoria e solo dopo applicando un filtraggio.

Poiché si utilizza EF, è possibile sfruttare le proprietà di esecuzione posticipate di IQueryable.Controllare:

.NET Entity Framework - IEnumerable VS. IQueryable

Should a Repository return IEnumerable , IQueryable or List?


Aggiornamento: Facendo seguito a tuo commento Si dovrebbe anche controllare:

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

+0

Il GetAll è solo un metodo di esempio, l'obiettivo principale è sulla parte filtrante. Creo quindi un metodo nel repository per ogni utilizzo? Ma non il .Where (...) funziona come una selezione sql con una clausola where? –

+0

Solo quando si utilizza LINQ per le entità e per questo è necessario un "IQueryable". –

+0

Sì. Ho un metodo Get tat is IQueryable in ther epository, in modo che il repository possa gestire tutte le condizioni che uno getta su di esso. Un metodo GetALlUsers() mi fa licenziare le persone. È inefficiente come l'inferno. Tirando 100.9000 utenti per ottenere quello per nome - no. – TomTom

2

si dovrebbe sempre cercare di recuperare il meno il più possibile dal database. E dovresti quindi fare tutto il filtraggio nelle tue classi di repository.

Molti articoli suggeriscono di creare e utilizzare repository generici. Ma non funzioneranno molto bene quando la tua applicazione cresce. Vi consiglio di creare classi repository corretto con adeguati metodi di ricerca come:

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

Prima di tutto, si nasconde i dettagli di implementazione come il modo di identificare i nuovi utenti. Rende anche il codice più facile da capire e da estendere rispetto all'utilizzo di una query generica.

È inoltre possibile aggiungere alcune opzioni di filtraggio:

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

differenza @ JoãoAngelo NON consiglio di utilizzare IQueryable al di fuori del proprio repository. In questo modo si sposta l'esecuzione del database all'esterno della classe del repository. Ciò significa che nessun errore può essere gestito dal tuo repository.