Sto provando a progettare un modo semplice per estrapolare la persistenza dei dati dietro un'interfaccia, ma sto facendo fatica a capire quanto controllo a grana fine debba essere esposto agli strati superiori.
Limite, Filtro, Ordine, ecc.
La definizione di un'interfaccia per un repository di dati stupido è perfetta e dandy per le operazioni CRUD di base, ma per quanto riguarda tutte le altre funzionalità di database comuni come filtraggio dei risultati, limitazione, mappatura / riduzione e altre operazioni trasformative o condizionali? Questi tipi di operazioni violano il principio di responsabilità singola nel senso che un livello di persistenza dovrebbe essere solo una scatola nera stupida di recupero / permanenza e, di conseguenza, questa funzionalità sarebbe meglio implementata dal lato del codice chiamante (cioè, in un livello di servizio, o anche lato client)?
Trasformazioni lato client
Anche se ciò semplificherebbe enormemente il livello di persistenza, personalmente, ritengo che sarebbe abbastanza dispendioso eseguire queste operazioni lato client. Ad esempio, indipendentemente dal fatto che un utente esegua una query per un insieme di 10 risorse o 1000, il database dovrebbe restituire l'intero set di dati incorrere in costi di larghezza di banda e di memorizzazione nella cache, tra le altre cose. Anche molte di queste query sono probabilmente strongmente ottimizzate in modo nativo, e questo porterebbe tutto questo fuori dalla finestra.
Un'astrazione intelligente del database
D'altra parte, se dovessi esporre questa funzionalità del database nel livello di persistenza, aumenterebbe notevolmente la complessità dell'interfaccia e probabilmente finirà per sembrare un wrapper 1: 1 del driver del database (che è utile per scopi di test di simulazione, suppongo, ma in qualche modo sconfigge lo scopo di scrivere l'astrazione in primo luogo).
La mia domanda è: esiste una regola generale per la progettazione di un livello di astrazione del database per quale funzionalità esporre e cosa tenere nascosto?