Opzioni per la progettazione di un repository

2

Sto considerando come scrivere un repository per un nuovo progetto.

Mi piace l'idea di un repository generico come questo per le operazioni CRUD di base:

public class Repository<TEntity> : IRepository<TEntity> where TEntity : class, IEntity

Tuttavia, ho anche letto che questo è contro lo spirito del DDD. Pertanto, come compromesso, stavo pensando di creare un repository generico e quindi alcuni repository che ne ereditano, ad es. CustomerRepository: Repository ecc. Tuttavia, non riesco a trovare alcuna documentazione a supporto di questa idea.

D1) È ragionevole creare un repository di base?

Inoltre, sto provando a creare un repository per radice aggregata piuttosto che un repository per entità. Supponiamo di avere due classi, ad esempio Order e OrderItem (Order è la radice di aggresgate), quindi:

D2) È ragionevole che tutti gli accessi ai dati dell'Ordine Ordine vadano nel repository dell'Ordine (la radice aggregata)? vale a dire SELECT * FROM OrderItem WHERE OrderID=@OrderID (si traduce in LINQ).

    
posta w0051977 01.08.2017 - 00:13
fonte

2 risposte

5

In Domain Driven Design, il repository è il confine tra l'applicazione e il modello di dominio. È un'interfaccia di ruolo utilizzata dal programma per accedere alle radici aggregate (interfacce di ruolo proprie, che consentono l'accesso a specifici punti di ingresso nel modello di dominio).

Come regola, vuoi che l'interfaccia tra l'applicazione e il modello di dominio sia il più esplicita possibile, in modo che tu possa ottimizzare per ogni caso d'uso specifico.

Il problema fondamentale con il repository generico è che, senza informazioni su quale stato è rilevante, devi produrlo tutto.

Udi Dahan offre un bell'esempio di creazione di un repository che informa l'implementazione di come verrà utilizzato lo stato.

Detto questo, se vuoi usare un'implementazione generica dietro le quinte e introdurre implementazioni specializzate solo quando sai che i benefici fuori pesano i costi ... è perfettamente soddisfacente.

Anche il saggio di Udi solleva un punto interessante: l'interfaccia esplicita inserisce nel codice una descrizione migliore di ciò che sta accadendo, in cui un'interfaccia generica è più apprendibile .

This may seem like a lot of trouble to go to. It actually isn’t. It’s pretty much just a different way to package the code you already wrote. Yes, there are more interfaces, and probably more classes, but the amount of business logic code is the same. I’ve been able to keep performance high with this design, but increase its maintainability. I measure maintainability as both the amount of time, and number of changes that need to be made by a programmer familiar with the design. Learnability (?) is often called maintainability, but I think that it’s something else. This design may not be as learnable– meaning it would take a given programmer longer to learn this design than the previous one. I submit that the increased maintainability outweighs the increased learnability substantially.

    
risposta data 01.08.2017 - 03:01
fonte
3

A1) Di solito no. Considera un% diCustomerRepository concreto. Potrebbe accedere ai dati in un database SQL, in un database di documenti, direttamente in memoria, ecc. Potrebbe essere utile denominarlo dopo la tecnologia dell'archivio dati su cui si basa, ad es. %codice%. Per astrarre la concreta tecnologia di accesso ai dati e ottenere test più semplici, si creerebbe un MongoCustomerRepository che la percentuale di% di co_de concreta implementerebbe. La creazione di un ICustomerRepository come interfaccia di repository di base sarebbe quindi astrazione di un'astrazione. Per questo motivo, non servirebbe molto vantaggio oltre a salvare poche righe di codice dell'interfaccia ripetuta e potrebbe potenzialmente confondere gli utenti.

Un'idea simile è quella di creare un repository di base generico che esponga i metodi di query che contengono, ad esempio, un'espressione LINQ o un'altra forma di una query. Oltre ad astrarre astrazioni, queste finiscono quasi sempre per essere traballanti in quanto non si può astrarre correttamente il linguaggio di query che potrebbe essere utilizzato da un'implementazione concreta. E non si dovrebbe, dal momento che le query su ORM Frameworks e sui driver del database sono complete e saranno comunque nascoste dietro un'interfaccia.

A2) Le interfacce del repository devono essere allineate in base ai casi di utilizzo aziendale. Inoltre, entità e oggetti valore possono avere solo riferimenti a oggetti all'interno dello stesso aggregato e altre radici aggregate. Questo è così che la radice aggregata può garantire la coerenza e la corretta convalida delle regole aziendali all'interno dell'aggregato. Pertanto, se CustomerRepository è la radice di un aggregato che contiene oggetti IRepository value, è inappropriato restituire Order s direttamente da un repository. Invece, si dovrebbe restituire un OrderItem che sappia come soddisfare i casi d'uso che riguardano il suo OrderItem s.

    
risposta data 02.08.2017 - 10:13
fonte

Leggi altre domande sui tag