2014-10-31 19 views
7

Ho implementato il seguente schema per jbogard:Come gestire gli eventi di dominio generati dai gestori di eventi?

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

Immaginate la seguente entità Coupon ed evento CouponActivatedEvent:

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)); 
    } 
} 

Il seguente gestore di eventi 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 
     } 
    } 
} 

Il seguente SaveChanges override sul DbContext (Entity Framework 6), tratta dal post del blog di jbogard:

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(); 
} 

Se ora attiviamo un coupon, questo aumenterà il CouponActivatedEvent. Quando si chiama SaveChanges, verrà eseguito il gestore, e UserReceivedCreditEvent e verrà sollevata CreditCreatedEvent. Non saranno gestiti comunque. Sto fraintendendo il modello? Oppure l'override SaveChanges non è appropriato?

Ho preso in considerazione la creazione di un ciclo che verrà ripetuto fino a quando non vengono sollevati nuovi eventi prima di passare a base.SaveChanges(); ... ma sono preoccupato che creerò casualmente cicli infiniti. In questo modo:

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(); 
} 

risposta

12

Sì, le cose frainteso. Un evento di dominio non è come un evento C#, è un messaggio su cosa è cambiato nel dominio. Una regola è che un evento è qualcosa che è accaduto, è nel passato. Quindi, un gestore di eventi semplicemente non può (non dovrebbe) cambiare l'evento, è come cambiare il passato.

È CouponActivatedHandler dovrebbe almeno avere l'entità utente formare un repository poi aggiornarlo con il numero di crediti, quindi salvarlo, quindi pubblicare un UserCreditsAdded evento. Ancora meglio, il gestore deve semplicemente creare e inviare un comando AddCreditsToUser.

Con il modello Eventi dominio, un'operazione è semplicemente una catena di comando-> evento-> comando-> evento ecc. Il gestore eventi è solitamente un servizio (o un metodo in uno) che si occupa solo di quel bit. Il mittente dell'evento non saprà nulla dell'handler e viceversa.

Come regola generale, un oggetto Dominio genera un evento quando il suo stato è cambiato. Un servizio prenderà quegli eventi quindi li invierà a un bus di servizio (per una semplice app, è sufficiente un contenitore DI) che li pubblicherà per essere gestiti da chiunque sia interessato (questo significa servizi dall'app locale o altre app sottoscritte a quel bus).

mai dimenticare che Domain Events è un modello ad alto livello usato quando si fa l'architettura di un app, non è solo un altro modo per fare gli eventi degli oggetti (come gli eventi C# s ').

+0

Grazie, hai chiarito più cose per me. Sei a conoscenza di un progetto di esempio disegnato nel modo in cui descrivi? Penso di avere l'idea, non sono sicuro di come implementarlo correttamente. – Korijn

+4

Esempio, non proprio. Ma comincia a farlo, la pratica rende perfetti. Fai attenzione a ciò che ti sembra ingombrante, prova a fare il refattore, ecc. Il DDD è appreso eseguendolo. – MikeSW

+0

Ora capisco, in particolare che * i gestori di eventi reagiscono a cose che si sono verificate in passato * ha spiegato molto. – Korijn

Problemi correlati