Domanda

Ho un modello di dominio che ha il concetto di un editor e di un progetto.

Un editor possiede un numero di progetti e un progetto ha non solo un proprietario dell'editor, ma anche un numero di membri dell'editor. Pertanto, un editor ha anche un numero di "uniti" " Progetti.

Sto adottando un approccio DDD per modellare questo e usare il modello di repository per la persistenza. Tuttavia, non riesco ancora a individuare il modello abbastanza bene per determinare come dovrei farlo.

Sto lavorando sul presupposto che Editor e Project siano potenzialmente nello stesso aggregato, con il root come Editor. Posso quindi ottenere un editor e quindi elencare i suoi progetti, e da lì posso elencare gli editor dei membri dei progetti.

Tuttavia, se mi è permesso recuperare solo i redattori dal mio repository, questo non significa che devo caricare tutti i progetti dal repository quando ottengo l'editor che li possiede? E se voglio caricare pigro gli Editor membri, anche il Progetto ha bisogno di un riferimento al repository?

In alternativa, se divido l'aggregato e ho un repository Editor e un repository Project, come devo gestire una transazione tra i due, come quando un nuovo Progetto viene aggiunto a un Editor? Ad esempio:

Editor e = new Editor("Editor Name");
editorRepository.Add(e);

Project p = e.CreateProject("Project Name");
projectRepository.Add(p);    // These two lines
editorRepository.Save(e);    // should be atomic

Sto interpretando male l'intento del modello di deposito?

È stato utile?

Soluzione

  

Sto interpretando male l'intento del modello di deposito?

Sto per dire "sì", ma sappi che io e ogni persona con cui ho lavorato abbiamo chiesto la stessa cosa per lo stesso motivo ... "Non stai pensando in quarta dimensione , Marty " ;.

Semplificiamo un po 'e atteniamoci ai costruttori invece di creare prima i metodi:

Editor e = new Editor("Editor Name");
e = editorRepository.Add(e);

Project p = new Project("Project Name", e);
p = projectRepository.Add(p);

Al di sotto, il repository del tuo progetto memorizza sempre un proprietario valido ( p.EditorId ) nei dati del progetto mentre viene creato, e comunque popolerai nuovamente i progetti di un editor, sarà lì. Ecco perché è una buona pratica mettere tutte le proprietà richieste nei costruttori. Se non vuoi passare l'intero oggetto, lo farà solo e.Id .

  

E se voglio caricare pigro gli Editor membri, anche il Progetto ha bisogno di un riferimento al repository?

Ora, su come popolare nuovamente i progetti di un editor su richiesta, hai un paio di scelte a seconda di cosa stai cercando. Straight Repository dice che vuoi:

IEnumerable<Project> list = projectRepository.GetAllProjects()
                                .Where(x => x.editorId == e.Id);

Ma dove metterlo? Non all'interno di Project o dell'Editor, hai ragione, o dovranno avere accesso ai repository e non va bene. Lo snippet di cui sopra è liberamente accoppiato, ma non è riutilizzabile da solo. Hai appena raggiunto i limiti del Repository Pattern.

Il prossimo è un layer adattatore per la tua applicazione, con una fonte condivisa di repository ( StaticServiceWrapper ) e una sorta di oggetto EditorAdapter (o Aggregate o come li chiameresti) o ora tu può mescolare metodi di estensione in grado di parlare fluentemente con tutti i repository necessari. Non l'ho fatto esattamente in un sistema di produzione, ma per mostrarti un esempio conciso:

public static class Aggregators
{
    // one to one, easy
    public static Editor GetOwner(this Project p)
    {
        return StaticServiceWrapper.editorRep.GetEditorById(p.editorId);
    }

    // one to many, medium
    public static IEnumerable<Project> GetProjects(this Editor e) 
    { 
        return StaticServiceWrapper.projectRep.GetAllProjects()
                .Where(x => x.editorId == e.Id);
    }

    // many to many, harder
    public static IEnumerable<Editor> GetMembers(this Project p)
    {
        var list = StaticServiceWrapper.projectMemberMap.GetAllMemberMaps()
                        .Where(x => x.projectId == p.projectId);

        foreach ( var item in list )
            yield return StaticServiceWrapper.editorRep.GetEditorById(item.editorId);
    }
}

Fondamentalmente, una volta fatto GetAll, GetById, Aggiungi, Aggiorna, Rimuovi oggetto repository, devi lasciare da sole le associazioni e passare alla gerarchia di oggetti / livelli nelle parti divertenti come Adattatori e cache e Logica aziendale ( " Oh, mio! " ).

Altri suggerimenti

Che ne dici di dividere le responsabilità in un EditorOwner e un EditorMember?

Senza conoscere il tuo dominio, immagino che avrebbero responsabilità diverse - ad esempio, EditorOwner potrebbe essere piuttosto ricco (e potrebbe essere la radice aggregata), ma il Progetto potrebbe aver bisogno solo di conoscere un numero limitato di membri, quindi l'oggetto EditorMember potrebbe essere abbastanza leggero.

Questi oggetti di dominio possono anche riguardare Utenti, ma ciò sarebbe in un altro contesto.

Questo aiuta le cose, o semplicemente le rende più complicate?

Dipende dalle esigenze della tua applicazione. Se è un grosso problema caricare tutti i progetti per un determinato editor, prova un modello di caricamento pigro come un Proxy virtuale .

Per quanto riguarda il caricamento pigramente dei membri Editor di un progetto, se si utilizza Virtual Proxy, non vedo alcun problema nell'iniezione del proxy con EditorRepository poiché non considero il proxy come parte del dominio.

Se si divide l'aggregato, è possibile esaminare il modello Unit of Work come uno soluzione all'atomicità. Questo problema, tuttavia, non è univoco per DDD e sono sicuro che ci sono altre soluzioni per il comportamento transazionale.

Qui hai 2 relazioni diverse, una per la proprietà e una per l'appartenenza.

La relazione di proprietà è semplice per molti (un proprietario per ciascun progetto). Il rapporto di appartenenza è da molti a molti (molti redattori per progetto, molti progetti per editore).

È possibile fornire una proprietà Owner sulla classe Project e un metodo su ProjectRepository per ottenere tutti i progetti di proprietà di un editor specifico.

Per le molte relazioni, fornire una proprietà Members sulla classe Project e un metodo su ProjectRepository per ottenere tutti i progetti contenenti l'editor specificato come membro.

Sembra anche che i redattori ed i progetti siano entità, probabilmente dividerei l'aggregato, ma forse quei termini hanno un significato specifico nel tuo contesto che lo rende sotto-entità di un aggregato.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top