Я реализовал следующую картину по 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();
}
Спасибо, вы уточнили несколько вещей для меня. Вы знаете пример проекта, разработанный так, как вы описываете? Я думаю, что я понял, я просто не знаю, как правильно его реализовать. – Korijn
Пример, не совсем. Но начните это делать, практика делает совершенным. Делайте, обратите внимание на то, что кажется громоздким, попробуйте рефакторинг и т. Д. DDD изучается, делая это. – MikeSW
Я получаю это сейчас, в частности, что * обработчики событий реагируют на вещи, которые произошли в прошлом * объяснили многое. – Korijn