小编Dmi*_*diu的帖子

在持久化聚合之前发布域事件是否安全?

在许多不同的项目中,我看到了两种不同的方法来提升域事件.

  1. 直接从聚合中提升域事件.例如,假设您有Customer聚合,这里面是一个方法:

    public virtual void ChangeEmail(string email)
    {
        if(this.Email != email)
        {
            this.Email = email;
            DomainEvents.Raise<CustomerChangedEmail>(new CustomerChangedEmail(email));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

    我可以看到这种方法存在两个问题.第一个是无论聚合是否持久化,都会引发事件.想象一下,如果您想在注册成功后向客户发送电子邮件.将引发事件"CustomerChangedEmail",即使未保存聚合,某些IEmailSender也会发送电子邮件.当前实现的第二个问题是每个事件都应该是不可变的.所以问题是如何初始化其"OccuredOn"属性?只在里面汇总!合乎逻辑,对吧!它迫使我将ISystemClock(系统时间抽象)传递给聚合中的每个方法!Whaaat ??? 难道你不觉得这个设计很脆弱吗?以下是我们将要提出的建议:

    public virtual void ChangeEmail(string email, ISystemClock systemClock)
    {
        if(this.Email != email)
        {
            this.Email = email;
            DomainEvents.Raise<CustomerChangedEmail>(new CustomerChangedEmail(email, systemClock.DateTimeNow));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)
  2. 第二种方法是采用Event Sourcing模式建议的方法.在每个聚合上,我们定义一个未列出事件的(List)列表.请注意UncommitedEvent不是域事件!它甚至没有OccuredOn属性.现在,当在Customer Aggregate上调用ChangeEmail方法时,我们不会提出任何内容.我们只是将事件保存到我们的聚合中存在的uncommitedEvents集合.像这样:

    public virtual void ChangeEmail(string email)
    {
        if(this.Email != email)
        {
            this.Email = email;
            UncommitedEvents.Add(new CustomerChangedEmail(email));
        }
    }
    
    Run Code Online (Sandbox Code Playgroud)

那么,什么时候实际的域事件被提出?此职责委托给持久层.在ICustomerRepository中,我们可以访问ISystemClock,因为我们可以轻松地将其注入到存储库中.在ICustomerRepository的Save()方法中,我们应该从Aggregate中提取所有uncommitedEvents,并为每个事件创建一个DomainEvent.然后我们在新创建的Domain Event上设置OccuredOn属性.然后,在IN ONE TRANSACTION中,我们保存聚合并发布所有域事件.通过这种方式,我们将确保所有事件都将在具有聚合持久性的跨国界限中提升.
我对这种方法不喜欢什么?我不想为同一事件创建2种不同的类型,即对于CustomerChangedEmail行为,我应该有CustomerChangedEmailUncommited类型和CustomerChangedEmailDomainEvent.只有一种类型会很好.请分享您对此主题的体验!

c# dns domain-driven-design

8
推荐指数
1
解决办法
1500
查看次数

是否应该从应用程序层抛出域异常?

我正在阅读Vaughn Vernon的书-实现域驱动设计。有一个项目管理应用程序的示例。有聚合,例如BacklogItem,Sprint等。如果我在Domain层中定义了BacklogItemNotFoundException。我的Rest适配器应该抓住它并转换为NotFoundHttpResult吗?还是任何其他破碎的不变异常,例如:EmailPatternBrokenException或TooManyCharactersForNameException或应在Rest适配器(端口和适配器体系结构)中处理的任何东西,然后重新转换为Rest响应?如果是,这意味着RestAdapter应该具有对Domain层的引用?这就是困扰我的...

domain-driven-design exception-handling hexagonal-architecture

5
推荐指数
3
解决办法
1699
查看次数