gpt4 book ai didi

c# - 如何处理事件处理程序引发的域事件?

转载 作者:太空狗 更新时间:2023-10-29 18:22:04 26 4
gpt4 key购买 nike

我已经通过 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 时,将执行处理程序,并引发 UserReceivedCreditEventCreditCreatedEvent。他们不会被处理。我误解了模式吗?还是 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();
}

最佳答案

是的,你误解了事情。领域事件不像 C# 事件,它是关于领域中发生了什么变化的消息。一个规则是事件是发生的事情,它是过去的事情。因此,事件处理程序根本不能(不应该)更改事件,就像更改过去一样。

CouponActivatedHandler 至少应该从存储库中获取用户实体,然后用积分数更新它,然后保存它,然后发布一个 UserCreditsAdded 事件。更好的是,处理程序应该只创建并发送命令 AddCreditsToUser

对于域事件模式,一个操作只是一系列命令->事件->命令->事件等。事件处理程序通常是一个服务(或其中的一个方法),它只处理那个位。事件的发送者不会知道有关处理程序的任何信息,反之亦然。

作为经验法则,域对象在其状态发生变化时生成一个事件。服务将接收这些事件,然后将它们发送到服务总线(对于一个简单的应用程序,一个 DI 容器就足够了),该服务总线将发布它们以供任何感兴趣的人处理(这意味着来自本地应用程序或订阅该总线的其他应用程序的服务).

永远不要忘记领域事件是在构建应用程序时使用的高级模式,它不仅仅是处理对象事件(如 C# 的事件)的另一种方式。

关于c# - 如何处理事件处理程序引发的域事件?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26677718/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com