Wie sollen wir neue aggregierte Wurzeln in der cqrs-Architektur erstellen? In diesem Beispiel möchte ich ein neues aggregiertes Stamm-AR2 erstellen, das auf das erste AR1 verweist.
Ich erstelle AR2 mit der AR1-Methode als Ausgangspunkt. Bisher sehe ich nur wenige Möglichkeiten:
- Innerhalb der Methode in AR1
createAr2RootOpt1
konnte ichnew AR2()
dieses Objekt sofort mithilfe eines Domänendienstes mit Zugriff auf das Repository aufrufen und in der Datenbank speichern. Ich könnte ein Ereignis in der ersten aggregierten Wurzel ausgeben, z.
SholdCreateAR2Event
und dann eine zustandslose Saga haben, die darauf reagiert und einen Befehl ausgibt,CreateAR2Command
der dann verarbeitet wird und tatsächlich AR2 erstellt und ausgibtAR2CreatedEvent
. Bei Verwendung der Ereignisbeschaffung wirdSholdCreateAR2Event
diese nicht im Ereignisspeicher beibehalten, da sie den Status des ersten aggregierten Stamms nicht beeinflusst. (Oder sollten wir dies trotzdem im Event Store speichern?)class AR1{ Integer id; DomainService ds; //OPTION 1 void createAr2RootOpt1(){ AR2 ar2 = new AR2(); ds.saveToRepo(ar2); } //OPTION 2 void createAr2RootOpt2(){ publishEvent(new SholdCreateAR2Event()); //we don't need this event. Shoud it still be preserved in event store? } } class AR2{ Integer id; Integer ar1Id; void handle(CreateAR2Command command){ //init this AR with values and save publishEvent(AR2CreatedEvent()); //used for projections afterwards and saved inside AR2 event store } } class Saga{ void handle(SholdCreateAR2Event ev){ emitCommand(new CreateAR2Command()); } }
Was ist der richtige Weg, dies zu tun?
quelle
AR1WasCreated
? Sollte es seinAR2WasCreated
? Wenn ich Ihre Logik verwende, gebe ich ein Ereignis aus,AR2WasCreated
bevor es tatsächlich erstellt wird. Das Speichern dieses Ereignisses im Ereignisprotokoll von AR1 scheint problematisch zu sein, da ich diese Daten in AR1 nicht benötige (es ändert nichts in AR1).AR1WasCreated
-> SAGA (hat Regel, wenn A1 erstellt wurde, dann erstellen Sie A2) ->CreateAR2Command
->AR2WasCreated
.Schöpfungsmuster sind komisch .
Udi Dahan hat einige nützliche Dinge über das allgemeine Problem zu sagen: Erstellen Sie keine aggregierten Wurzeln . Der grundlegende Punkt ist, dass Aggregate nicht einfach aus dem Nichts herausspringen und dass es eine Domänensprache gibt, die beschreibt, wie sie angezeigt werden und die in Ihrem Domänenmodell erfasst werden sollte.
Es besteht die Tendenz, dass die Entität in Ihrem Domänenmodell, die den Befehl verarbeitet, nicht die Entität ist, die durch die Transaktion geändert wird. Das ist nicht falsch; Es ist einfach komisch (im Vergleich zu den Fällen, in denen Sie eine Entität bitten, sich selbst zu ändern.
Ihr zweiter Ansatz ist ebenfalls in Ordnung. "Ereignisse, die wir auslösen, ohne sie tatsächlich in der Datenbank zu speichern" werden manchmal als "Domänenereignisse" bezeichnet.
Die Grundidee besteht darin, dass der Befehlshandler innerhalb derselben Transaktion das Ereignis auslöst, das entlang des Busses zu einem Ereignishandler geleitet wird, der es dem zweiten Aggregat ermöglicht, sich selbst zu erstellen. Vielleicht erhalten Sie einen etwas besseren Code-Zusammenhalt.
Hinweis: In Systemen mit Ereignisquellen verwenden Sie Ereignisse normalerweise nicht auf diese Weise.
Hinweis: Ereignisnamen sind normalerweise in der Vergangenheitsform - ShouldCrateAR2 hat die falsche Schreibweise.
Ja, wenn Sie nur ein Ereignis auf den Synchronbus werfen, um Remotecode auszuführen, sollten Sie dieses Ereignis nicht im Buch der Aufzeichnung speichern. Es ist nur ein Implementierungsdetail in dieser Größenordnung.
Vermeiden Sie es, zwei verschiedene Ereignisströme in derselben Transaktion zu ändern. Wenn diese Erstellung auch eine Änderung an AR1 darstellt, besteht die übliche Antwort darin, AR1 in dieser Transaktion mit einem asynchronen Abonnenten für die Ereignisse zu ändern, die für das Auslösen des Befehls zum Erstellen von AR2 verantwortlich sind.
Idempotente Befehlsbehandlung hilft hier sehr.
quelle
AR1.doSmthn(AR2 param)
da jede von mir erstellte Leseprojektion keine vollständigen Daten enthält, die ich benötige (nur AR2 verfügt über vollständige Daten).