Penso che la domanda debba essere divisa in due parti. Innanzitutto, qual è il ruolo dei POCO che rappresentano gli oggetti del database e, in secondo luogo, il modo migliore per strutturare i repository per gestirli.
In risposta alla prima domanda, sembra che tu abbia scelto di mappare i tuoi POCO direttamente agli oggetti del database: una classe rappresenta esattamente sulla tabella o una vista. Ma c'è anche un'altra opzione, che consiste nel fare in modo che una classe rappresenti una entità - l'oggetto concettuale che i tuoi dati descrivono. Ad esempio, invece di CarView
, CarHeaderTable
e CarVersionTable
(o qualsiasi schema di denominazione che usi), il tuo POCO sarebbe solo un Car
.
I principali pro e contro di queste due opzioni così come li vedo:
Mappatura Pro-Direct
- È molto semplice! Non è necessario affrontare alcuna complessità nella mappatura degli oggetti di database su POCO.
- Offre ancora molti dei vantaggi di un ORM (o una soluzione arrotolata a mano che coinvolge la mappatura di oggetti di database in POCO). Rimuova comunque il codice ripetitivo che coinvolge i dati di estrazione in entrata e in uscita da
DataTable
s, stai ancora isolando il tuo codice di accesso ai dati da doversi preoccupare di SQL e così via.
POCO pro-concettuali
- Piuttosto che schermare il tuo codice dalle preoccupazioni di SQL , puoi proteggerlo completamente dalle preoccupazioni di persistenza (almeno per quanto riguarda il design della tua classe). Ora qualsiasi codice che vuole solo occuparsi di
Car
può gestire un Car
, senza doversi preoccupare se si tratta di un Car
progettato per essere letto o un Car
progettato per essere scritto in e se sono solo i bit immutabili di Car
o solo i bit mutabili, o entrambi. Come il tuo design è valido, in realtà non fa nulla per affrontare la mancata corrispondenza dell'impedenza (Robert C. Martin parla di questo qui )
- Riduci il numero di classi che sono realmente lì solo per fornire le stesse informazioni in modi diversi. Non so cosa fai attualmente quando vuoi aggiungere un metodo (magari un semplice calcolo) a uno di questi POCO. È vietato? Lo duplichi in tutte le classi che rappresentano la stessa cosa? Crei un
CarHelper
che fa cose che Car
dovrebbe davvero essere in grado di fare da solo? Con una sola classe Car
non è più un problema.
Se scegli la seconda delle due opzioni di cui sopra, questa domanda praticamente scompare. Ma forse hai già preso in considerazione quanto sopra, o lo fai ora e decidi che, a conti fatti, ti impegni con il mapping diretto degli oggetti da POCO a DB. In tal caso, ti rimane ancora la domanda su quale sia l'opzione migliore.
Per cominciare, come ha detto Robert Harvey, probabilmente non vuoi Table
e View
nella tua terminologia, dato che è molto specifico per i database. Readable
e Writeable
potrebbero essere termini migliori, per entrambe le versioni.
Oltre a ciò, ritengo che l'opzione migliore sia quella che si adatta ai consumatori di questi repository. Il codice che legge di solito vuole anche scrivere, e viceversa? Quindi confezionarli insieme, come nella seconda versione, è probabilmente una buona idea.
Come Eric King ha accennato ai commenti, partire da un repository di base è in realtà un modo un po 'arretrato: si inizia creando una struttura di ereditarietà progettata per affrontare preoccupazioni comuni / ripetute, senza in realtà alcuna ripetizione preoccupazioni da affrontare!
Quindi il mio consiglio sarebbe: creare un ICarRepository
e aggiungerlo come richiesto dal suo codice che consuma. Fai la stessa cosa con IPersonRepository
. Man mano che queste classi crescono, puoi fare un refactoring: trovi che mettere insieme i membri della tabella con quelli correlati alla vista è come una violazione dell'ISP (Interface Segregation Principle)? Quindi dividerli. C'è una funzionalità ripetuta e generica? Quindi estrarre una classe base Repository<T>
(o Repository<TWriteable,TReadable>
). In questo modo invece di fare progetti basati su congetture, creerai un design guidato da come viene utilizzato.