2014-10-31 5 views
7

Ich habe das folgende Muster von jbogard implementiert:Wie behandelt man Domain-Events, die von Event-Handlern ausgelöst werden?

http://lostechies.com/jimmybogard/2014/05/13/a-better-domain-events-pattern/

die CouponActivatedEventCoupon und Ereignisse folgende Einheit Stellen Sie sich vor:

public class Coupon : DomainEntity 
{ 
    public virtual User User { get; private set; } 

    // ...omitted... 

    public void Activate(User user) 
    { 
     if (User != null) 
      throw new InvalidOperationException("Coupon already activated"); 

     User = user; 

     Events.Add(new CouponActivatedEvent(this)); 
    } 
} 

Die folgenden Ereignishandler CouponActivatedHandler:

public class CouponActivatedHandler : IDomainEventHandler<CouponActivatedEvent> 
{ 
    public void Handle(CouponActivatedEvent e) 
    { 
     // user gets 5 credits because coupon was activated 
     for (int i = 0; i < 5; i++) 
     { 
      e.Coupon.User.AddCredit(); // raises UserReceivedCreditEvent and CreditCreatedEvent 
     } 
    } 
} 

Das folgende SaveChanges Überschreibung auf DbContext (Entity Framework 6), von jbogard Blog-Post genommen:

public override int SaveChanges() 
{ 
    var domainEventEntities = ChangeTracker.Entries<IDomainEntity>() 
     .Select(po => po.Entity) 
     .Where(po => po.Events.Any()) 
     .ToArray(); 

    foreach (var entity in domainEventEntities) 
    { 
     var events = entity.Events.ToArray(); 
     entity.Events.Clear(); 
     foreach (var domainEvent in events) 
     { 
      _dispatcher.Dispatch(domainEvent); 
     } 
    } 

    return base.SaveChanges(); 
} 

Wenn wir jetzt einen Gutschein aktivieren, wird dies die CouponActivatedEvent erhöhen. Beim Aufruf von SaveChanges wird der Handler ausgeführt und UserReceivedCreditEvent und CreditCreatedEvent werden ausgelöst. Sie werden jedoch nicht behandelt. Verkenne ich das Muster? Oder ist die SaveChanges Übersteuerung nicht geeignet?

Ich habe überlegt, eine Schleife zu erstellen, die wiederholt wird, bis keine neuen Ereignisse ausgelöst werden, bevor Sie zu base.SaveChanges(); weitergehen ... aber ich bin besorgt, dass ich aus Versehen Endlosschleifen erstellen werde. Wie so:

public override int SaveChanges() 
{ 
    do 
    { 
     var domainEventEntities = ChangeTracker.Entries<IDomainEntity>() 
      .Select(po => po.Entity) 
      .Where(po => po.Events.Any()) 
      .ToArray(); 

     foreach (var entity in domainEventEntities) 
     { 
      var events = entity.Events.ToArray(); 
      entity.Events.Clear(); 
      foreach (var domainEvent in events) 
      { 
       _dispatcher.Dispatch(domainEvent); 
      } 
     } 
    } 
    while (ChangeTracker.Entries<IDomainEntity>().Any(po => po.Entity.Events.Any())); 

    return base.SaveChanges(); 
} 

Antwort

12

Ja, Sie missverstanden Dinge. Ein Domänenereignis ist nicht wie ein C# -Ereignis, es ist eine Nachricht darüber, was sich in der Domäne geändert hat. Eine Regel ist, dass ein Ereignis etwas ist, das passiert ist, es ist in der Vergangenheit. Daher kann ein Event-Handler das Ereignis einfach nicht ändern (es sollte nicht), es ist so, als würde man die Vergangenheit ändern.

Sie CouponActivatedHandler sollte zumindest bekommen die Entität Benutzer ein Repository bilden dann mit der Anzahl der Credits aktualisieren, dann speichern, dann veröffentlichen ein UserCreditsAdded Ereignis. Noch besser, der Handler sollte nur einen Befehl erstellen und senden AddCreditsToUser.

Mit Domain-Events-Muster ist eine Operation einfach eine Kette von command-> event-> command-> event usw. Der Event-Handler ist normalerweise ein Service (oder eine Methode in einem), der nur dieses Bit behandelt. Der Absender des Ereignisses weiß nichts über den Handler und umgekehrt.

Als Daumenregel generiert ein Domänenobjekt ein Ereignis, wenn sich sein Status geändert hat. Ein Dienst nimmt diese Ereignisse und sendet sie dann an einen Servicebus (für eine einfache App genügt ein DI-Container), der sie für alle Interessierten veröffentlicht (dh Dienste von der lokalen App oder anderen Apps, die diesen Bus abonniert haben)).

Vergessen Sie nie, dass Domain-Events ein High-Level-Muster ist, das bei der Architektur einer App verwendet wird, es ist nicht nur eine andere Möglichkeit, Objektereignisse (wie C# -Ereignisse) auszuführen.

+0

Danke, Sie haben mehrere Dinge für mich geklärt. Kennen Sie ein Beispielprojekt, wie Sie es beschreiben? Ich denke, ich habe die Idee, ich bin mir nur unsicher, wie ich es richtig umsetzen soll. – Korijn

+4

Beispiel, nicht wirklich. Aber fang an, Übung macht den Meister. Beachten Sie, was sich mühsam anfühlt, versuchen Sie es zu refaktorieren usw. DDD wird dadurch erlernt. – MikeSW

+0

Ich bekomme es jetzt, speziell dass * Event-Handler auf Dinge reagieren, die in der Vergangenheit aufgetreten sind * viel erklärt. – Korijn

Verwandte Themen