DDD Aggrega radice con aggregati complessi

1

Ho un AR e non riesco a capire il modo migliore per creare / modificare alcuni complessi aggregati in esso contenuti. Questi aggregati hanno molti parametri quindi ho deciso all'interno del modello di dominio di utilizzare oggetti valore anziché tipi primitivi.

public class Load : AggregateRoot
{
    public virtual string Name { get; protected set; }

    public virtual User ResponsibilityOf { get; protected set; }

    public virtual User AssignedTo { get; protected set; }

    public virtual User CoveredBy { get; protected set; }

    public virtual State State { get; protected set; }

    public virtual Cargo Cargo { get; protected set; }

    public virtual Guid CustomerId { get; protected set; }

    public virtual IList<Run> Runs { get; protected set; }

    public Load(Guid customerId, string name) : this()
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentNullException(nameof(name));

        Name = name;
        CustomerId = customerId;
        Runs = new List<Run>();
    }
}

Runs è una collezione di Value Objects e Run è definita di seguito. È un buon esempio del problema che sto affrontando perché richiede diversi parametri e alcuni di essi sono oggetti valore.

public sealed class Run : ValueObject<Run>
{
    public int Order { get; private set; }

    public Location Origin { get; private set; }

    public Location Destination { get; private set; }

    public Guid CarrierId { get; private set; }

    private Run() { }

    public Run(Guid carrierId, Location origin, Location destination, int order = 0) : this()
    {
        if (carrierId == Guid.Empty)
            throw new ArgumentNullException(nameof(carrierId));

        Origin = origin ?? throw new ArgumentNullException(nameof(origin));
        Destination = destination ?? throw new ArgumentNullException(nameof(destination));
        Order = order;
        CarrierId = carrierId;
    }
}

Voglio aggiungere metodi per le operazioni CRUD per le corse in AR (caricamento) e non so come affrontarlo. Questo sarebbe un compito banale se Origin e Destination erano primitivi o hanno solo preso uno o due parametri per creare un'istanza. Ma l'origine e la destinazione sono oggetti valore.

public sealed class Location: ValueObject<Location>
{
    public string Name { get; private set; }

    public Address Address { get;private  set; }

    public string Notes { get; private set; }

    public string Directions { get; private set; }

    public int CustomerId { get; private set; }

    public string HoursOfOperation { get; private set; }

    public Phone Phone { get; private set; }
}

Quindi quando vado ad aggiungere i miei metodi CRUD al carico principale di aggregazione, sono perso sul modo migliore per raggiungere questo obiettivo. Potrei aggiungere il seguente, ma non sembra il modo DDD per risolvere questo problema perché al di fuori del dominio non si dovrebbe sapere quale Run è giusto?

void AddRun(Run run);
void RemoveRun(Run run);
void UpdateRun(Guid id, Run run );

Se al di fuori del dominio non si conosce cosa sia Run, dovrei usare i tipi primitivi come parametri e questo diventerebbe molto veloce perché ci sarebbero molti parametri per costruire l'oggetto.

Modifica 1: Corretti alcuni aspetti indicati nelle risposte.

    
posta JasonlPrice 24.10.2017 - 06:01
fonte

1 risposta

2

I have an AR and I can't figure out the best way to create/edit some of the complex aggregates contained in it.

Attenzione: l'ortografia è disattivata. AR non contiene aggregati, la denominazione è il contrario.

An AGGREGATE is a cluster of associated objects that we treat as a unit for the purpose of data changes. Each AGGREGATE has a root and a boundary.

Concettualmente, l'aggregato è un grafico di entità (forse complesse) , con la radice aggregata come una di quelle entità nel grafico.

Inoltre: gli oggetti valore sono solitamente immutabili - non dovresti avere setter.

So when I go to add my CRUD methods to the Aggregate Root Load, I'm lost on how best to achieve this goal. I could add the following, but it doesn't seem like the DDD way to solve this problem because outside of the domain should not know what Run is right?

Ci sono un paio di possibili risposte all'enigma.

In questo modello, sembra che tu abbia molte proprietà di cui hai bisogno per fare riferimento per ottenere qualcosa. Quindi qualcosa come un messaggio http che descrive un cambiamento avrà un documento JSON complicato.

Un modo per trasformare quel documento in qualcosa che il modello comprende è usare un modello di builder. Dai all'applicazione piccole mini fabbriche per costruire le strutture di dati di cui ha bisogno per parlare al modello. Questa è una cosa assolutamente ragionevole da fare.

Un'altra possibile risposta è esaminare il tuo modello con più attenzione; i modelli di dominio riguardano principalmente il cambiamento; non sono negozi di documenti glorificati. Le informazioni che il modello non ha bisogno dovrebbero essere archiviate in un documento da qualche altra parte. Ad esempio, se un'esecuzione è una risposta a un "ordine", allora l'esecuzione potrebbe avere una copia del numero dell'ordine e una copia dei dati che effettivamente ha bisogno di fare il suo lavoro, ma non tutto il resto.

(Allo stesso modo: se hai un CustomerId nel tuo valore, probabilmente non hai nemmeno bisogno di un valore Customer. Usa l'id per cercare i dettagli che normalmente non usi.)

Unfortunately most of the Run information will be needed by the model.

Se è così, allora lo è, e dovrai gestirlo. Ma respingi questa ipotesi: se confondi i dati devi prendere una decisione con i dati necessari per creare una vista, finirai per fare più lavoro per te stesso.

Would the factories go in the domain layer?

È una prima ipotesi plausibile - di solito iniziamo con l'assunzione di una raccolta implicita di primitive agnostiche (qualunque sia la lingua in cui ci accorgiamo al momento). Evans ha aggregato aggregati, repository e fabbriche insieme nel capitolo 6 del blue book, considerandoli tutti parte del livello del dominio.

Penso che sia un po 'più corretto pensare a queste fabbriche come parte di un adattatore che consente all'applicazione di comunicare con il modello.

    
risposta data 24.10.2017 - 06:46
fonte

Leggi altre domande sui tag