Separazione delle preoccupazioni tra repository e servizio in DDD con entità complesse

3

Questo probabilmente sembra un esempio di domanda basata sull'opinione pubblica, ma in realtà sto cercando una logica su come decidere correttamente, credo che ci sia una soluzione corretta che può essere sostenuta da argomenti solidi (ecco perché ho scelto SO e la speranza è in realtà non solo basata sull'opinione pubblica, ma posso sbagliarmi, se ti senti così, per favore lascia un commento in un commento). Non riesco a decodificare quanto lontano andare con SoC in DDD e se sia ok avere oggetti di dominio per lo più vuoti.

Abbiamo .NET, DDD, che utilizza principalmente EF come nostro ORM in repository, la nostra applicazione risiede in Azure. Per query complesse, utilizziamo stored procedure che restituiscono multiset (a causa di SQL di Azure): quindi una query = un round trip sul server (ne vale la pena, la query viene eseguita generalmente su > 10 tabelle separate, nessun join, quindi richiederebbe molti viaggi di andata e ritorno).

Per semplicità, immagina oggetto di dominio chiamato NavigationItem, che ha più titoli (in lingue diverse), gli elementi sono memorizzati in una tabella, i titoli localizzati sono memorizzati in un'altra tabella, dove la chiave esterna è il titolo dell'articolo contiene id cultura.

L'oggetto di navigazione potrebbe essere simile a questo:

public class NavigationItem
{
    public int FileRecordId { get; set; }

    public int? ParentId { get; set; }

...

    public Dictionary<int, string> Title { get; set; }
}

Quindi l'oggetto dominio, restituito dal repository, viene costruito (nel repository) in questo modo:

// load list of navigation items
var reader = command.ExecuteReader();
navigation.Items = ((IObjectContextAdapter)_context).ObjectContext.Translate<NavigationItem>(reader).ToList();

// process localized titles
reader.NextResult();
var titles = ((IObjectContextAdapter)_context).ObjectContext.Translate<TitleInfo>(reader).ToList();

// associate titles, so the whole NavigationItem is constructed
foreach (var item in navigation.Items)
{
    item.Title = titles.Where(t => t.FileRecordId == item.FileRecordId).ToDictionary(key => key.CultureId, value => value.Title);
}

Questo è un semplice esempio, giusto per ottenere il punto - la mia domanda è, non sarebbe meglio restituire solo la lista degli elementi di navigazione (dove dovrei omettere la proprietà Title) e l'elenco dei titoli e combinarli in un servizio livello, quando si crea un oggetto DTD? Il repository è responsabile della persistenza e del recupero dei dati persistenti, e non sono sicuro, se questo è semplicemente "troppo". D'altra parte, il requisito del repository potrebbe essere semplicemente "datemi l'intera entità con titoli". La separazione delle preoccupazioni è naturalmente un buon modo, ma non sono sicuro che si tratti ancora del deposito.

Per favore prendi questo come un semplice esempio, la mia domanda è più generale - in questo esempio, ogni oggetto di dominio NavigationItem contiene Title, quindi si sente che è OK farlo in repository. Ma quando abbiamo etities più complesse, c'è un altro problema - ad esempio, ogni file ha proprietà comuni, come Name. Alcuni file hanno proprietà immagine, lo stesso hanno anche proprietà documento PDF, alcuni hanno titoli localizzati ... altri no. In questo caso, sembra molto più "naturale" avere un'entità (file comune) e restituire lista, elenco, elenco, ... dal repository e combinarlo nel servizio. Oppure, d'altra parte, eseguire tutte le traduzioni nel repository, ma significherebbe che il file oggetto dominio (radice aggregata) conterrà entità come ImageInfo, TitleInfo, ecc., Che nella maggior parte dei casi saranno nulle.

Quale approccio - e principalmente, perché - consiglieresti?

EDIT: per essere più specifici - dal punto di vista del DDD, è ok mantenere Entity parzialmente vuota e qualche volta nel repository recupera solo alcune proprietà (o tutte quante volte), o è un approccio migliore per separare tale entità con quelle più piccole e restituire una entità che aggrega gli elenchi di tutte le possibili entità? Credo che ci possa essere una risposta ragionevole, tipicamente "sì, l'entità parzialmente inizializzata è ok", o "no, è sbagliato e dovresti sempre usare le entità granulari possibili", ecc.

    
posta Robert Goldwein 21.09.2014 - 02:57
fonte

1 risposta

1

Sembra che tu stia utilizzando le entità di dominio per entrambe le operazioni di dominio (comandi, che modificano lo stato dell'applicazione) e le query (che non modificano lo stato dell'applicazione ma restituiscono i dati per l'utente). I problemi che descrivi sono un risultato diretto del tentativo di ottenere che l'entità a dominio singolo svolga entrambi i lavori, che non si combinano molto bene.

Il mio consiglio è di leggere su CQRS (Segragation di responsabilità della query di comando) ad es. CQRS di Martin Fowler e prova a limitare le entità di dominio a recuperare solo i dati di cui hanno bisogno per completare l'operazione di dominio. Anche se la quantità di classi e interfacce crescerà, la tua applicazione diventerà molto più semplice e più manutenibile a causa della maggiore aderenza al Principio di responsabilità singola .

Inoltre, la scelta di oggetti di dominio e in particolare di Radici aggregate mi porta a mettere in discussione la validità del modello di dominio. Un file è davvero una tale entità, che ha un significato terribile per gli uomini d'affari? Che tipo di operazioni fai sul file e qual è il loro valore per il business? L'intera idea di Domain Driven Design è quella di identificare le entità aziendali reali su cui agire, come se non si avesse un computer. Un ordine è un esempio comune. Le operazioni su quella radice di Aggragate sarebbero "Invia", "Annulla" ecc. Il file è solo un problema infrastrutturale, che spesso non ha alcun valore o posto nella logica del dominio.

    
risposta data 02.07.2015 - 21:45
fonte

Leggi altre domande sui tag