Sommario
Quando si scrivono i metodi per interrogare le entità correlate, è meglio avere un unico metodo per tutte le entità correlate o metodi separati per ciascuna combinazione?
Problema completo
Sto scrivendo le classi di repository per un progetto .NET MVC in cui ciascun repository è responsabile per l'esecuzione di query per un tipo di entità specifico. Sto usando Dapper, quindi tutte le domande sono scritte a mano. Tutti gli repository implementano un'interfaccia IRepository<TEntity>
, che ha metodo TEntity FindById(id)
.
Recuperare solo l'entità è ovviamente molto semplice, ma mi trovo di fronte a un dilemma quando si tratta di andare a prendere i figli ei nipoti dell'entità e così via. Spesso, perché un'entità sia utilizzabile, ha bisogno di alcuni o tutti i suoi discendenti. Inizialmente ho scritto FindById
per restituire l'entità con tutti i discendenti, che soddisfa tutti i casi d'uso, ma è anche dispendiosa in molti casi in cui ho bisogno solo di diversi discendenti.
Ho scritto i singoli metodi per il recupero di varie combinazioni. FindByIdWithChildA
o FindByIdWithChildBAndGrandChildC
e così via. Il problema qui è che i nomi dei metodi continuano a essere sempre più lunghi, il che li rende difficili da leggere e spreca molto spazio nel codice.
La mia prossima idea era di accettare vari valori di enum flag che designavano i discendenti da restituire. Questo ha funzionato bene per i bambini immediati, ma quando sono arrivato ai nipoti e oltre ho avuto tante combinazioni possibili da implementare, e molti di loro non avevano senso o non sarebbero stati usati.
Quando scrivo tutto questo testo, mi sembra quasi di scrivere un ORM cattivo invece di repository. Ciò ha certamente rallentato notevolmente lo sviluppo e si è distolto dall'effettiva implementazione di nuove funzionalità.
L'ovvia soluzione sbagliata è non utilizzare i join SQL e fare in modo che i repository uniscano le entità e le raccolte di entità usando LINQ. L'utilizzo di LINQ con EntityFramework potrebbe essere un'opzione, ma non credo che la soluzione debba passare a un'altra libreria.
Dovrei semplicemente semplificare e fare in modo che il singolo metodo / query restituisca tutto? In caso contrario, qual è il modo migliore per implementare concisamente metodi separati?
Questa risposta indica che un metodo di tipo FindByIdWithChild
è normale, ma non posso immaginare che essere buona pratica per query complesse.
Chiarimento
Quindi le mie entità sono Sport, Divisione, SkillLevel e TeamType. Ogni sport ha un elenco di divisioni, SkillLevels e TeamTypes. Ogni divisione ha un singolo TeamType e un elenco di SkillLevels.
Supponiamo che voglio una divisione con il suo genitore Sport, il suo TeamType e tutti i suoi SkillLevels. Dovrei fare:
-
DivisionRepository.FindById(id)
che restituisce tutte queste proprietà, ignorando ogni caso in cui voglio solo una divisione o una divisione e sport, divisione e tipo di squadra, ecc. -
DivisionRepository.FindById(id, BitFlagQueryScope)
che ha un grande casino di un'implementazione per risolvere tutti i possibili flag, alcuni dei quali potrebbero non essere necessari. -
DivisionRepository.FindByIdWithSportAndTeamTypeAndSkillLevels(id)
e uno di questi metodi per ogni combinazione di cui ho bisogno.
In tutti e tre i casi, sto facendo un viaggio nel database. È solo questione di come strutturo il mio codice.
Esempio aggiuntivo, supponiamo che io voglia uno sport con solo i suoi TeamTypes. Altrove avrò bisogno di uno sport con i suoi SkillLevels, ecc. Stesse domande come sopra. Sto facendo solo un viaggio nel database, ma dovrei usare un codice diverso per queste diverse query, o semplicemente prendere tutto e scartare / non usare l'eccesso?
Chiarimento aggiuntivo
Nel caso ci sia qualcosa di sbagliato nel mio design in generale, ecco come sto usando le entità:
Action(string id)
{
var sport = SportRepository.FindById(id); // This needs to either return everything associated with the entity or be changed to allow specification
var model = new SportDisplayModel(sport);
return View(model);
}
Ho due modelli, $ Entity $ DisplayModel e $ Entity $ EditModel, e li uso per ogni vista.