Design patterns 域事件处理程序和数据库更改事件

Design patterns 域事件处理程序和数据库更改事件,design-patterns,domain-driven-design,cqrs,Design Patterns,Domain Driven Design,Cqrs,我是域驱动和CQR的新手,对事件处理机制有点困惑 Domian事件正在触发发生的事件。例如,创建一个帐户 public class Account: AggregateRoot{ public Account(Guid id) { Apply(new AccountCreatedEvent { AggregateRootId = id }); } } public class AccountCratedEvent: Doma

我是域驱动和CQR的新手,对事件处理机制有点困惑

Domian事件正在触发发生的事件。例如,创建一个帐户

public class Account: AggregateRoot{        
      public Account(Guid id)
      {
          Apply(new AccountCreatedEvent { AggregateRootId = id });
      }
}
public class AccountCratedEvent: DomainEvent{
}

我认为这是域的内部事件机制。因此,我无法向新帐户所有者发送电子邮件。因为新帐户尚未保存到数据库。那么,我是否应该创建一个新的事件处理程序以在保存数据库后填充?

是的,这是一个常见的问题。根据域名的具体性质,您可能希望选择两个可能的位置中的一个发送电子邮件:

最容易放置它的地方是作为事件处理程序。这需要考虑以下几点:

  • 所有事件处理程序是否成功完成并不重要
  • 事件和/或读取模型具有发送消息所需的所有信息。重要的是,读取模型不依赖于更新的完成(最终的一致性问题)
  • 您的消息发送基础结构很简单
如果这些事情中有任何一个是问题,那么您需要使用流程管理器。这是一个可以监听事件并发出命令的设备。在这种情况下,成功完成所有事件后,发出命令发送电子邮件

我已经写了一篇更详细的博客文章来讨论这个话题。您可以在此处阅读:

Apply()事件并不等于立即发送事件,尽管您的域模型将立即处理事件,如:

public class Account: AggregateRoot{        
    public Account(Guid id)
    {
        Apply(new AccountCreatedEvent { AggregateRootId = id });
    }
    public void handle(AccountCreatedEvent event) 
    {
        this.id = event.AggregateRootId
        this.status = "New"
    }
}

Apply()的实现通常只处理聚合上的事件,并缓存引发的事件。其他对象,通常由存储库负责获取缓存的事件并发出它们。

帐户创建事件的可能副本是域本身的事件吗?我可以在保存数据库后发送电子邮件。不,根据您的定义,AccountCreatedEvent不是“内部”事件。这是一个可以发布的事件。但是,当执行Apply()时,发布不会立即发生,相反,Apply()的实现通常将事件缓存在工作单元中。事件应该在提交单元或工作后发布。您的博客评论已关闭,我认为您做错了;-)为什么你认为事件和命令处于同一个级别?但是根据一些神奇的关键字,它会触发事件或调用命令。我不确定我是否理解你的意思。在CQRS ES设置中,命令表示操作。事件是表示状态更改的事件。我不确定我对“同一水平”的理解是什么。你能详细解释一下吗?嗨,代码书写者,我又读了你的博文,似乎我跳过了ProcessManager,对此我深表歉意。。我同意你的逻辑,当然ProcessManager可以写得更优雅,而不必打开或关闭,但那是另一回事。接下去,似乎很多开发人员对何时应该发送电子邮件以及何时应该执行命令感到困惑。像往常一样,问题是概念性的,人们通常认为电子邮件应该在事件处理程序(即AccountCreatedEvent)内执行。但事实上,正如你在博客文章中完美地描述的那样,一个命令总是由一个事件触发的,这一事实加上事件触发器中不应该存在逻辑的规则,使得理解imho很容易。