Devo utilizzare il repository nell'oggetto dominio o riportare l'oggetto dominio al livello di servizio?

10

Sono venuto da un mondo di script di transazione e sto appena iniziando a dare un'occhiata a DDD. Non sono sicuro del modo corretto di integrare una progettazione DDD con la persistenza del database. Questo è quello che ho:

Una classe di servizio chiamata OrganisationService la cui interfaccia contiene metodi per recuperare e salvare istanze di oggetti del dominio dell'organizzazione. L'organizzazione è una radice aggregata e ha altri dati ad essa correlati: membri e licenze. Primo database EF6 DBContext viene utilizzato all'interno di OrganisationService per recuperare le entità OrganisationDB e le relative entità MemberDB e LicenseDB. Questi vengono tutti trasformati in equivalenti della classe dell'oggetto dominio quando vengono recuperati da OrganisationService e caricati nell'oggetto dominio dell'organizzazione. Questo oggetto appare così:

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }
}

Non sto usando il modello di repository in OrganisationService ... Sto usando EF stesso come repository poiché sembra che EF6 abbia reso il repository ampiamente ridondante ora.

A questo punto del progetto l'oggetto del dominio Organizzazione è anemico: assomiglia alla classe Organizzazione EF POCO. La classe OrganisationService assomiglia molto ad un repository!

Ora ho bisogno di iniziare ad aggiungere logica. Questa logica include la gestione di licenze e membri di organizzazioni. Ora nei giorni degli script di transazione aggiungerei metodi in OrganisationService per gestire queste operazioni e chiamare in un repository per interagire con il DB, ma con DDD credo che questa logica dovrebbe essere incapsulata all'interno dell'oggetto stesso del dominio dell'organizzazione ...

Questo è il punto in cui non sono sicuro di cosa dovrei fare: avrò bisogno di mantenere questi dati nel database come parte della logica. Significa che dovrei usare DbContext all'interno dell'oggetto Dominio dell'organizzazione per fare questo? Sta usando il repository / EF all'interno della cattiva pratica degli oggetti di dominio? Se è così, a chi appartiene questa persistenza?

public class Organisation
{
    public IList<Member> Members { get; set; }
    public IList<License> Licenses { get; set; }

    public void AddLicensesToOrganisation(IList<License> licensesToAdd)
    {
        // Do validation/other stuff/

        // And now Save to the DB???
        using(var context = new EFContext())
        {
            context.Licenses.Add(...
        }

        // Add to the Licenses collection in Memory
        Licenses.AddRange(licensesToAdd);
    }
}

Dovrei invece semplicemente mormorare l'oggetto dominio dell'organizzazione in memoria e poi rimandarlo a OrganisationService per la persistenza? Poi devo tenere traccia di ciò che effettivamente è cambiato sull'oggetto (che è ciò che EF fa ai suoi POCO!). Mi sembra di sentire che EF non è solo una sostituzione del repository, ma potrebbe anche essere il livello del dominio!)

Qualsiasi consiglio qui è apprezzato.

    
posta MrLane 22.07.2014 - 10:34
fonte

2 risposte

2

Puoi adottare entrambi gli approcci e farlo funzionare bene: ovviamente ci sono pro e contro.

Entity Framework è sicuramente destinato a soffocare le tue entità di dominio. Funziona bene quando le entità di dominio e le entità dati sono le stesse classi. È molto più bello se puoi contare su EF per tenere traccia delle modifiche per te, e basta chiamare context.SaveChanges() quando hai finito con il tuo lavoro transazionale. Significa anche che i tuoi attributi di convalida non devono essere impostati due volte, una volta sui tuoi modelli di dominio e una volta sulle tue entità persistenti: cose come [Required] o [StringLength(x)] possono essere controllate nella tua logica aziendale , che consente di rilevare stati di dati non validi prima di provare a eseguire una transazione DB e ottenere EntityValidationException . Infine, è veloce da codificare: non è necessario scrivere un layer o un repository di mappatura, ma può invece lavorare direttamente con il contesto EF. È già un repository e un'unità di lavoro, quindi gli ulteriori livelli di astrazione non realizzano nulla.

Uno svantaggio di combinare il tuo dominio e le entità persistenti è che ti ritroverai con un mucchio di [NotMapped] di attributi sparsi nelle tue proprietà. Spesso, vorrete proprietà specifiche per il dominio che sono o filtri get-only sui dati persistenti, o che vengono impostate successivamente nella vostra logica aziendale e che non vengono ripristinate nel vostro database. Alcune volte, ti consigliamo di esprimere i tuoi dati nei tuoi modelli di dominio in un modo che non funziona molto bene con un database - ad esempio, quando usi l'enumerazione, Entity li mapperà a una colonna int - ma forse tu vuoi mapparli ad un string leggibile dall'uomo, quindi non devi consultare una ricerca quando esamini il database. Quindi si finisce con una proprietà string che è mappata, una proprietà enum che non è (ma ottiene la stringa e le mappe all'enum) e un'API che espone entrambi! Allo stesso modo, se si desidera combinare tipi complessi (tabelle) in contesti, è possibile concludere con mapped OtherTableId e una proprietà ComplexType non mappata, entrambe esposte come pubbliche sulla classe. Ciò può creare confusione per qualcuno che non ha familiarità con il progetto e inutilmente gonfia i tuoi modelli di dominio.

Più complesso è il mio dominio / logica aziendale, più restrittivo o ingombrante trovo che combini il mio dominio e le entità persistenti. Per progetti con scadenze brevi o che non esprimono un livello aziendale complesso, ritengo che l'utilizzo di entità EF per entrambi gli scopi sia appropriato e che non sia necessario estrapolare il dominio dalla persistenza. Per i progetti che richiedono la massima facilità di estensione, o che devono esprimere una logica molto complicata, penso che sia meglio separare i due e affrontare la complessità extra di persistenza.

Un trucco per evitare il problema del tracciamento manuale delle modifiche all'entità è archiviare l'ID entità persistente corrispondente nel modello di dominio. Questo può essere riempito automaticamente dal tuo livello di mappatura. Quindi, quando è necessario mantenere una modifica su EF, recuperare l'entità persistente pertinente prima facendo qualsiasi mappatura. Quindi quando mappi le modifiche, EF le rileverà automaticamente, e puoi chiamare context.SaveChanges() senza doverle tracciare a mano.

public class OrganisationService
{
    public void PersistLicenses(IList<DomainLicenses> licenses) 
    {
        using (var context = new EFContext()) 
        {
            foreach (DomainLicense license in licenses) 
            {
                var persistedLicense = context.Licenses.Find(pl => pl.Id == license.PersistedId);
                MappingService.Map(persistedLicense, license); //Right-left mapping
                context.Update(persistedLicense);
            }
            context.SaveChanges();
        }
    }
}
    
risposta data 23.07.2014 - 03:44
fonte
3

Non conosco EF6, ma altri ORM gestiscono questo in modo trasparente, quindi non dovrai aggiungere esplicitamente le licenze al contesto, ma le rileverà quando salverà le modifiche. Quindi il metodo sarà in

public void AddLicenses(IEnumerable<License> licensesToAdd)
{
    // Do validation/other stuff/
    // Add to the Licenses collection in Memory
    Licenses.AddRange(licensesToAdd);
}

e il codice che lo circonda

var someOrg = Load(orgId);

someOrg.AddLicenses(someLicences);

SaveChanges();
    
risposta data 22.07.2014 - 16:12
fonte

Leggi altre domande sui tag