Persistenz- und Domänenereignisse mit persistenten ignoranten Objekten

Ich habe mich mit domänengetriebenem Design befasstDomain-Ereignisse. Ich mag die Trennung der Bedenken, die diese Ereignisse mit sich bringen. Ich bin auf ein Problem mit der Reihenfolge gestoßen, ein Domänenobjekt beizubehalten und Domänenereignisse auszulösen. Ich möchte Ereignisse in den Domänenobjekten auslösen, möchte jedoch, dass sie keine Persistenz besitzen.

Ich habe ein Basic erstelltShoppingCartService, mit diesemCheckout Methode:

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 vonOrder würde anhebenOrderCreated Ereignis, das von bestimmten Handlern behandelt werden kann. Ich möchte jedoch nicht, dass diese Ereignisse ausgelöst werden, wenn die Entität noch nicht vorhanden ist oder wenn das Bestehen auf irgendeine Weise fehlschlägt.

Um dieses Problem zu lösen, habe ich verschiedene Lösungen gefunden:

1. Ereignisse im Service auslösen:

Anstatt das Ereignis im Domänenobjekt auszulösen, könnte ich Ereignisse im Dienst auslösen. In diesem Fall ist dieCheckout Methode würde die erhöhenOrderCreated Veranstaltung. Einer der Nachteile dieses Ansatzes ist, dass beim Betrachten derOrder Domänenobjekt, es ist nicht klar, welche Ereignisse durch welche Methoden ausgelöst werden. Außerdem muss ein Entwickler daran denken, das Ereignis auszulösen, wenn eine Bestellung an einer anderen Stelle erstellt wird. Es fühlt sich nicht richtig an.

2. Domänenereignisse in der Warteschlange

Eine andere Möglichkeit besteht darin, Domänenereignisse in die Warteschlange zu stellen und sie auszulösen, wenn das Bestehen erfolgreich war. Dies könnte erreicht werden durch ausing Aussage zum Beispiel:

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

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

DasQueueEvents<T> Methode würde einen Booleschen Wert auf setzentrue und dasDomainEvents.Raise<T> Methode würde das Ereignis in die Warteschlange stellen, anstatt es direkt auszuführen. Im dispose Rückruf vonQueueEvent<T>werden die Ereignisse in der Warteschlange ausgeführt, wodurch sichergestellt wird, dass das Bestehen bereits stattgefunden hat. Dies scheint ziemlich schwierig zu sein, und der Dienst musste wissen, welches Ereignis im Domänenobjekt ausgelöst wird. In dem von mir bereitgestellten Beispiel wird auch nur eine Art von auszulösendem Ereignis unterstützt, dies könnte jedoch umgangen werden.

3. Behalten Sie das Domänenereignis bei

Ich könnte das Objekt mithilfe eines Domänenereignisses beibehalten. Dies scheint in Ordnung zu sein, mit Ausnahme der Tatsache, dass der Event-Handler, der das Objekt persistiert, zuerst ausgeführt werden sollte. Ich habe jedoch irgendwo gelesen, dass Domain-Events nicht von einer bestimmten Ausführungsreihenfolge abhängen sollten. Vielleicht ist das nicht so wichtig und Domain-Ereignisse könnten irgendwie wissen, in welcher Reihenfolge die Handler ausgeführt werden sollen. Beispiel: Angenommen, ich habe eine Schnittstelle, die ein Domänenereignis definiertHandlerwürde eine Implementierung so aussehen:

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

Wenn ich weiterhin einen Ereignishandler verwenden möchte, würde ich einen anderen Handler erstellen, der von derselben Schnittstelle abgeleitet ist:

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

JetztNotifyCustomer Das Verhalten hängt von der Reihenfolge ab, die in der Datenbank gespeichert wirdPersistOrder Eventhandler sollte zuerst ausgeführt werden. Ist es akzeptabel, dass diese Handler beispielsweise eine Eigenschaft einführen, die die Reihenfolge ihrer Ausführung angibt? Ein Schnappschuss von der Implementierung desDomainEvents.Raise<OrderCreated>() Methode:

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

Nun ist meine Frage, habe ich noch andere Möglichkeiten? Vermisse ich etwas? Und was halten Sie von den von mir vorgeschlagenen Lösungen?

Antworten auf die Frage(1)

Ihre Antwort auf die Frage