首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何处理事件处理程序引发的域事件?

如何处理事件处理程序引发的域事件?
EN

Stack Overflow用户
提问于 2014-10-31 15:04:06
回答 2查看 4.3K关注 0票数 10

我通过jbogard实现了以下模式:

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

想象下面的实体Coupon和事件CouponActivatedEvent

代码语言:javascript
运行
复制
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

代码语言:javascript
运行
复制
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 (实体框架6),摘自jbogard的博客文章:

代码语言:javascript
运行
复制
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();之前,该循环将一直重复直到没有引发任何新的事件。但我担心我会不小心造成无穷无尽的循环。就像这样:

代码语言:javascript
运行
复制
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();
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-10-31 19:02:49

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

您的CouponActivatedHandler至少应该让用户实体形成一个存储库,然后用学分数更新它,然后保存它,然后发布一个UserCreditsAdded事件。更好的是,处理程序应该只创建和发送一个命令AddCreditsToUser。

对于Domain模式,一个操作只是一个命令链-> event -> command-> event等等。事件处理程序通常是一个服务(或一个方法中的一个),它只处理该位。事件的发送方将不知道任何有关处理程序的信息,反之亦然。

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

不要忘记,在执行应用程序的架构时,Domain是一种高级模式,它不仅仅是处理对象事件的另一种方式(比如C#的事件)。

票数 16
EN

Stack Overflow用户

发布于 2022-07-25 06:13:25

域事件的链接实现不处理事件处理程序引发的潜在嵌套事件。如果你仔细阅读提交人的评论,他自己也曾提到他“试图避免”。

海事组织,你用循环实现的东西是有意义的。但是,如果你不确定进入一个不确定的回路,我建议你在那里实现一个断路器模式。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/26677718

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档