6

Ich habe auf Domain-driven Design in Verbindung mit domain events studiert. Ich mag die Trennungen von Sorgen, die diese Ereignisse bieten. Ich stieß auf ein Problem mit der Reihenfolge des Behaltens eines Domänenobjekts und des Anhebens von Domänenereignissen. Ich möchte Ereignisse in den Domain-Objekten auslösen, doch ich möchte, dass sie unwissend bleiben.Persistence und Domain Events mit Persistenz Ignoranten Objekte

Ich habe eine grundlegendes ShoppingCartService, mit dieser Checkout Methode erstellt:

public void Checkout(IEnumerable<ShoppingCartItem> cart, Customer customer) 
{ 
    var order = new Order(cart, customer); 

    _orderRepositorty.Add(order); 
    _unitOfWork.Commit(); 
} 

In diesem Beispiel ist der Konstruktor von Order würde ein OrderCreated Ereignis auslösen, die von bestimmten Handler gehandhabt werden kann. Ich möchte jedoch nicht, dass diese Ereignisse ausgelöst werden, wenn die Entität noch nicht persistiert ist oder wenn das Fortbestehen irgendwie fehlschlägt.

um dieses Problem zu lösen, habe ich mehrere Lösungen herausgefunden haben:

1. Heben Ereignisse im Dienst:

Statt das Ereignis in der Domain-Objekt zu heben, ich Ereignisse in den Dienst erhöhen könnte. In diesem Fall würde die Checkout Methode das Ereignis OrderCreated auslösen. Einer der Nachteile dieses Ansatzes besteht darin, dass bei der Suche nach dem Domänenobjekt Order nicht klar ist, welche Ereignisse durch welche Methoden ausgelöst werden. Außerdem muss ein Entwickler daran denken, das Ereignis anzuheben, wenn eine Bestellung an anderer Stelle erstellt wird. Es fühlt sich nicht richtig an.


2. Queue Domain Ereignisse

Eine weitere Option ist Domain Ereignisse in die Warteschlange und sie zu erhöhen, wenn es gelungen persistierenden. Dies könnte durch eine using Anweisung zum Beispiel erreicht werden:

using (DomainEvents.QueueEvents<OrderCreated>()) 
{ 
    var order = new Order(cart, customer); 

    _orderRepositorty.Add(order); 
    _unitOfWork.Commit(); 
} 

Die QueueEvents<T> Methode würde setzt einen boolean true und die DomainEvents.Raise<T> Methode würde die Ereigniswarteschlange, anstatt sie direkt ausgeführt werden. Im Dispo-Callback von QueueEvent<T> werden die in der Warteschlange stehenden Ereignisse ausgeführt, die sicherstellen, dass das Persistierende bereits passiert ist. Dies scheint ziemlich schwierig zu sein und es erforderte, dass der Dienst weiß, welches Ereignis im Domänenobjekt ausgelöst wird. In dem Beispiel, das ich zur Verfügung gestellt habe, unterstützt es auch nur einen Ereignistyp, der jedoch behoben werden könnte.


3. Persist in Domain-Ereignisse

ich das Objekt mit einem Domäne Ereignisse bestehen könnte. Dies scheint in Ordnung zu sein, abgesehen von der Tatsache, dass der Ereignishandler, der das Objekt persistent hält, zuerst ausgeführt werden sollte, aber ich habe irgendwo gelesen, dass Domänenereignisse nicht auf einer bestimmten Ausführungsreihenfolge beruhen sollten. Vielleicht ist das nicht so wichtig und Domänenereignisse könnten irgendwie wissen, in welcher Reihenfolge die Handler ausgeführt werden sollten.Zum Beispiel: Angenommen, ich habe eine Schnittstelle einer Domäne Ereignis Handler definieren, wäre eine Umsetzung wie folgt aussehen:

public class NotifyCustomer : IDomainEventHandler<OrderCreated> 
{ 
    public void Handle(OrderCreated args) 
    { 
     // ... 
    } 
} 

Wenn ich auch bei der Verwendung einen Event-Handler behandeln persistierenden wollen, würde ich einen anderen Handler erstellen, Ableiten aus der gleichen Schnittstelle:

public class PersistOrder : IDomainEventHandler<OrderCreated> 
    { 
     public void Handle(OrderCreated args) 
     { 
      // ... 
     } 
    } 
} 

Jetzt hängt NotifyCustomer Verhalten auf der Reihenfolge, in der Datenbank gespeichert werden, so dass die PersistOrder Event-Handler sollten zuerst auszuführen. Ist es akzeptabel, dass diese Handler beispielsweise eine Eigenschaft einführen, die die Reihenfolge ihrer Ausführung angibt? Ein Schnapp aus der Umsetzung der DomainEvents.Raise<OrderCreated>() Methode:

foreach (var handler in Container.ResolveAll<IDomainEventHandler<OrderCreated>>().OrderBy(h => h.Order)) 
{ 
    handler.Handle(args); 
} 


Nun meine Frage ist, habe ich keine andere Optionen? Fehle ich etwas? Und was halten Sie von den vorgeschlagenen Lösungen?

+0

Haben Sie darüber nachgedacht, eine Fabrik- oder Fabrikmethode für die Erstellung neuer Bestellungen zu verwenden? Dies würde einen expliziten Unterschied zwischen der Instanziierung eines Auftragsobjekts und der Erstellung eines neuen Auftrags bedeuten. – tuespetre

Antwort

6

Entweder sind Ihre (transaktionalen) Ereignishandler in der (potenziell verteilten) Transaktion registriert oder Sie veröffentlichen/behandeln die Ereignisse nach der festgeschriebenen Transaktion. Ihre "QueueEvents" -Lösung erfüllt die Grundidee, aber es gibt elegantere Lösungen, z. B. die Veröffentlichung über das Repository oder den Ereignisspeicher. Ein Beispiel einen Blick auf

Sie könnten auch diese Fragen und Antworten nützlich finden:

CQRS: Storing events and publishing them - how do I do this in a safe way?

Event Aggregator Error Handling With Rollback


Update zu Punkt 3:

... aber ich habe irgendwo gelesen, dass Domain-Events folgen sollten Verlassen Sie sich nicht auf eine bestimmte Reihenfolge der Ausführung.

Unabhängig davon, wie Sie fortfahren, ist die Reihenfolge der Ereignisse absolut wichtig (innerhalb eines Aggregats).

Jetzt hängt das Verhalten von NotifyCustomer von der Reihenfolge ab, die in der Datenbank gespeichert wird, daher sollte der PersistOrder-Ereignishandler zuerst ausgeführt werden. Ist es akzeptabel, dass diese Handler beispielsweise eine Eigenschaft einführen, die die Reihenfolge ihrer Ausführung angibt?

Persisting und Umgang Ereignisse sind separate Bedenken - bestehen keine Ereignishandler verwenden. Zuerst beharren, dann handhaben.

+0

Vielen Dank für Ihre Antwort. Ich habe Punkt 3 aktualisiert, weil ich denke, dass Sie die Reihenfolge der Aufrufe _events_ und die Reihenfolge der Ausführung von _event handlers_ gemischt haben. Kannst du es dir anschauen? Danke im Voraus. –

+0

Ich habe meine Antwort aktualisiert, hoffe, es hilft. –

+0

Danke für Ihre Hilfe, ich denke, ich habe jetzt die Idee. –