2014-10-31 2 views
7

Я реализовал следующую картину по jbogard:Как обрабатывать события домена, вызванные обработчиками событий?

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

Представьте себе следующую лица Coupon и события 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)); 
    } 
} 

Следующий обработчик события 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 
     } 
    } 
} 

Следующие SaveChanges переопределение на DbContext (Entity Framework 6), взятый из блоге 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(); 
} 

Если мы теперь активировать купон, это поднимет CouponActivatedEvent. При вызове SaveChanges обработчик будет выполнен, а UserReceivedCreditEvent и CreditCreatedEvent будут подняты. Однако они не будут обработаны. Неужели я не понимаю шаблон? Или переопределение SaveChanges не подходит?

Я подумал о создании цикла, который будет повторяться до тех пор, пока новые события не будут подняты до перехода на base.SaveChanges(); ... но я беспокоюсь, что случайно создам бесконечные циклы. Например:

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

ответ

12

Да, вы неправильно поняли вещи. Событие домена не похоже на событие C#, это сообщение о том, что изменилось в домене. Одно правило состоит в том, что событие - это то, что произошло, это в прошлом. Таким образом, обработчик событий просто не может (он не должен) изменять событие, это как изменение прошлого.

Вы CouponActivatedHandler должен, по крайней мере, получить объект пользователя сформировать хранилище затем обновить его с количеством кредитов, а затем сохранить его, а затем опубликовать UserCreditsAdded события. Еще лучше, обработчик должен просто создать и отправить команду AddCreditsToUser.

С шаблоном событий домена операция представляет собой просто цепочку событий command-> event-> command-> и т. Д. Обработчик событий обычно представляет собой сервис (или метод в одном), который заботится только об этом бите. Отправитель события ничего не знает о обработчике и наоборот.

В качестве правила большого пальца объект Domain генерирует событие, когда его состояние изменилось. Служба будет принимать эти события, а затем отправлять их на служебную шину (для простого приложения достаточно контейнера DI), который будет публиковать их для обработки любым заинтересованным (это означает, что службы из локального приложения или других приложений, подписанных на эту шину).

Никогда не забывайте, что Domain Events - это шаблон высокого уровня, используемый при выполнении архитектуры приложения, это не просто другой способ делать события объекта (например, события C#).

+0

Спасибо, вы уточнили несколько вещей для меня. Вы знаете пример проекта, разработанный так, как вы описываете? Я думаю, что я понял, я просто не знаю, как правильно его реализовать. – Korijn

+4

Пример, не совсем. Но начните это делать, практика делает совершенным. Делайте, обратите внимание на то, что кажется громоздким, попробуйте рефакторинг и т. Д. DDD изучается, делая это. – MikeSW

+0

Я получаю это сейчас, в частности, что * обработчики событий реагируют на вещи, которые произошли в прошлом * объяснили многое. – Korijn

Смежные вопросы