DDD Agregátní hranice jeden pár a ani jeden mezi mnoha subjekty v jednom agregátu

0

Otázka

Viděl jsem tutoriál o DDD, ve které říká, že pokud mám agregát kořen SnackMachine, který má více než 30 podřízené prvky podřízené prvky by měly být v samostatné souhrnné. Například, SnackMachine má spoustu PurshaseLog (více než 30), a to je lepší pro PurshaseLog být v samostatné souhrnné. Proč je, že?

2
2

Důvodem pro omezení celkové velikosti úhrnu, protože vždycky zatížení plné agregovat do paměti a vždy budete ukládat plné agregátní transactionally. Velmi velký celek by mohlo způsobit technické problémy.

To znamená, že neexistuje žádná taková "30 podřízené prvky" pravidlo v souhrnné design a zní to jako svévolné pravidlo. Například, má méně velmi velké dítě prvků by mohlo být technicky horší, než mít 30 velmi lehký podřízené prvky. Dobrý způsob ukládání agregátů je jako json dokumenty, vzhledem k tomu, že budete vždy číst a psát dokumenty jako atomické operace. Pokud si myslíte, že tímto způsobem, budete si uvědomit, že souhrnný design, který znamená velmi velké, nebo dokonce někdy-rostoucí dítě sbírka bude nakonec způsobit problémy. A PurhaseLog zní jako stále rostoucí kolekce.

Druhá část pravidlo, které říká, "dejte ji v samostatné souhrnné" je také není správné. Nemusíte vytvářet agregáty, protože budete muset uložit některé údaje, a to nezapadá do stávajícího agregátu. Vytvoření agregátů, protože je třeba provést některé obchodní logiky a logiky bude potřebovat nějaké údaje, takže si dát obě věci dohromady, v celkovém.

Takže, i když to, co chcete vysvětlit ve své otázce, jsou věci, aby vzít v úvahu při navrhování agregáty, aby se zabránilo nutnosti technologických problémů, doporučuji si dát pozor na aktuální povinnosti agregátu.

Ve vašem příkladu, jaké jsou povinnosti SnackMachine? Dělá to opravdu potřebují (plné) seznam PurchaseLogs? Jaké operace bude SnackMachine vystavit? Řekněme, že to odhaluje PurchaseProduct(productId) a LoadProduct(productId, množství). K realizaci své obchodní logiky, tento agregát by třeba seznam výrobků a udržet počet jejich dostupné množství, ale to by nebylo třeba ukládat nákup protokolu. Místo, na každý Nákup, to mohl publikovat událost ProductPurchased(SnackMachineId, ProductId, Datum, AvailableQuantity). Pak externí systémy mohou přihlásit na tuto akci. Jeden účastník může zaregistrovat PurchaseLog pro účely podávání zpráv a další účastník mohl poslat někdo jiný stroj, když akcie byla nižší než X.

2021-11-17 23:29:06
2

Pokud PurchaseLog není jeho vlastní agregát pak to znamená, že to může jen být vyvolány nebo přidány jako součást dětské kolekce SnackMachine.

Proto pokaždé, když chcete přidat PurchaseLog, byste získat SnackMachine s jeho dítě PurchaseLogs, přidejte PurchaseLog do své sbírky. Pak uložit změny na jednotku práce.

Opravdu bylo třeba získat 30+ nákup záznamy, které jsou nadbytečné pro účely použití v případě vytvoření nového nákupu log?

Aplikační Vrstva - Varianta 1 (PurchaseLog je ve vlastnictví subjektu SnackMachine)

// Retrieve the snack machine from repo, along with child purchase logs
// Assuming 30 logs, this would retrieve 31 entities from the database that
// your unit of work will start tracking.
SnackMachine snackMachine = await _snackMachineRepository.GetByIdAsync(snackMachineId);

// Ask snack machine to add a new purchase log to its collection
snackMachine.AddPurchaseLog(date, quantity);

// Update
await _unitOfWork.SaveChangesAsync();

Aplikační Vrstva - Varianta 2 (PurchaseLog je agregát kořen)

// Get a snackmachine from the repo to make sure that one exists
// for the provided id.  (Only 1 entity retrieved);
SnackMachine snackMachine = await _snackMachineRepository.GetByIdAsync(snackMachineId);

// Create Purhcase log
PurchaseLog purchaseLog = new(
   snackMachine,
   date,
   quantity);

await _purchaseLogRepository.AddAsync(purchaseLog);

await _unitOfWork.SaveChangesAsync()

PurchaseLog - varianta 2

class PurchaseLog
{
    int _snackMachineId;
    DateTimne _date;
    int _quantity;

    PurchaseLog(
        SnackMachine snackMachine,
        DateTime date,
        int quantity)
    {
        _snackMachineId = snackMachine?.Id ?? throw new ArgumentNullException(nameof(snackMachine));
        _date = date;
        _quantity = quantity;
    }
}

Druhá varianta sleduje obrysy vašeho případu užití přesněji a také výsledky v mnohem méně i/o s databází.

2021-11-18 13:22:33

V jiných jazycích

Tato stránka je v jiných jazycích

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Español
..................................................................................................................
Slovenský
..................................................................................................................