Come progettare un modello di repository in grado di gestire il caricamento dei dati relazionali caso per uso?

5

Stiamo progettando un importante refactoring nel codebase del mio sistema aziendale. Uno dei punti refactoring è la (effettiva) definizione del modello di logica di business / dominio. In questo momento, ogni repository della base di codice recupererà solo ogni possibile parte di dati relativi all'entità, e per "ottimizzarlo", tutto verrà recuperato negli array piuttosto che negli oggetti (tecnicamente, hashmap di valori-chiave, ma in PHP essi ") chiamato array).

Ora vorrei introdurre l'uso effettivo degli oggetti del modello che incapsulano la logica aziendale (chiamando metodi come businessObject.canTransitionToNextProcessPhase() anziché eseguire un gruppo di if/else in un controller, con conseguente 0 leggibilità.

Per la prima parte di questo design, sto identificando quali dati relazionali sono must-load per ogni entità. Può essere facilmente identificato quando un'entità è dipendente. Ad esempio: un Entry dovrebbe sempre caricare Category e User (autore). Tuttavia, quando recuperi un User , non devi necessariamente caricare tutte le voci, i tuoi amici, Etc.

Ora, in alcuni casi particolari , quando carichi User , potresti voler caricare anche tutti Entries . Come progettare un pattern di repository che ti permetta di caricare i dati relazionali in quei casi particolari?

Ad esempio, prendi il metodo UserRepository@getById(int) :

Il metodo dovrebbe ricevere parametri di opzione che consentono di decidere se caricare relazioni aggiuntive diverse da quelle predefinite? (Ad esempio: ContactInfo è il valore predefinito, l'elenco di Entries è aggiuntivo).

Dovrebbe invece essere configato in un metodo concatenabile come repo.alsoLoad('entries').getById(id) ? (comunque questo sembra replicare l'API di ORM, penso).

Si noti che l'obiettivo di questo modello di schema di repository non è solo un livello che copre l'ORM senza necessità. I metodi recupereranno i dati in base ai casi di utilizzo aziendale: getAllInvoicesFromCurrentCycle() anziché getAll(hashamp /* with 5 key/values to be passed directly to the ORM's where clause*/) poiché quest'ultimo non fornisce alcun vantaggio (né leggibilità) (potrebbe anche essere utile utilizzare direttamente l'ORM).

Aggiornerò la domanda se sono necessari ulteriori chiarimenti.

    
posta Christopher Francisco 22.02.2017 - 22:42
fonte

1 risposta

2

Suggerirei di avere una classe UserRepository separata e una classe UserFriendRepository . UserFriendRepository può utilizzare un User o UserId nel suo costruttore.

(A meno che gli utenti e gli amici siano sempre trattati insieme e salvati insieme, allora vorrai una sola classe di repository, ma non penso che sia il tuo caso.)

L'intento del modello di repository è quello di offrire uno strato di semplicità, chiarezza (più facile per gli sviluppatori di lavorare con le classi User e Friend rispetto alle classi di accesso ai dati di basso livello) e la testabilità dell'unità. Si tratta di un livello di astrazione in cui, ad esempio, "il caching" potrebbe essere aggiunto (o modificato o rimosso) senza che il codice client lo sappia mai.

Addendum in base al commento:

Personalmente ho avuto più fortuna nel mantenere il livello del repository semplice (altrimenti mi ritrovo a implementare nuovamente l'ORM / essere legato in nodi). Preferisco chiamare UserFriendRepo.Get () quando necessario e UserOrderRepo.Get () quando necessario; piuttosto che un repository utente più complesso che può essere passato suggerimenti per caricare [amici] e [ordini].

Tuttavia un repository "più intelligente" potrebbe essere giustificato se il carico caricatosi e / o il caricamento pigro aiutano le prestazioni della tua particolare applicazione, o se è più intuitivo per gli sviluppatori del tuo negozio, ecc. I modelli sono solo approcci generali che sei libero di perfezionare.

    
risposta data 24.02.2017 - 20:51
fonte

Leggi altre domande sui tag