事件采购:触发他人的事件&重建国家

时间:2011-09-05 20:38:46

标签: domain-driven-design cqrs event-sourcing

我很难理解通过重播EventStore中的事件来重建模型时会发生什么,特别是当事件可能触发其他事件发生时。

例如,已经进行了10次购买的用户应该被提升为首选客户并收到一封电子邮件,向他们提供某些促销活动。

我们显然不希望每次为该用户重建模型时都会发送电子邮件,但是当我们重播第10个PurchaseMadeEvent时,我们如何阻止这种情况发生?

3 个答案:

答案 0 :(得分:10)

事件链接可能非常棘手并且容易失控,所以我会尽可能地避免它。例如,在您描述的场景中,我会引发UserPromotedEvent(甚至可能使用PromoteUserCommand),但我不会考虑将实际/物理发送电子邮件作为我的域的一部分。相反,我会为UserPromotedEvent创建额外的处理程序/非规范化程序,这可能会注册发送电子邮件的必要性。之后,另一个进程将收集尚未处理的电子邮件的信息并发送它们。这种方法可以缓解不完全可访问/可扩展的电子邮件网关可能出现的问题。

更一般地说 - 事件链接的需要经常表明你应该考虑为这个过程实现Saga

答案 1 :(得分:6)

你不应该从事件处理程序中引发事件 - 只是不要这样做!您应该使用sagas代替。

在您的情况下,saga订阅PurchaseMadeEvent并发出PromoteCustomer COMMAND,这会导致CustomerPromoted事件发生。同样,还有另一个saga订阅CustomerPromoted事件并发送SendEmailToPromotedCustomer命令。当您重播事件时 - 只是不要为CustomerPromoted事件订阅传奇。

这就是命令和事件之间的区别。理解它很重要。事件告诉已发生的事情,命令告诉将会发生什么。

答案 2 :(得分:3)

当您重播事件时,您不会重播生成这些事件所伴随的所有域逻辑。通常在您的域名方法中,您将举办活动;然后引发该事件应该更新该域对象的整体状态。

例如:

public class Purchase {
  private int _id;
  private string _name;
  private string _address;
  private double _amount;

  public Purchase(int id, string name, string address) {
    //do some business rule checking to determine if event is raised

    //perhaps send an email or do some logging
    //etc.
    if (should_i_raise_event) {
      ApplyEvent(new PurchaseMadeEvent() {
        ID = id,
        Name = name,
        Address = address
      });
    } 
  }

  public UpdatePurchase(int id, double amount) {
    //more checking to see if event is to be raised
    if (should_i_raise_event) {
      ApplyEvent(new PurchaseUpdatedEvent() {
        ID = id,
        Amount = amount
      });
    }
  }

  protected void OnPurchaseMade(PurchaseMadeEvent e){
    _id = e.ID;
    _name = e.Name;
    _address = e.Address;
  }

  protected void OnPurchaseUpdated(PurchaseUpdatedEvent e){
    _id = e.ID;
    _amount = e.Amount;
  }
}

在此示例中,当重播我的事件时,将执行OnPurchaseMade事件处理程序,而不是域对象构造函数。与PurchaseUpdatedEvent相同 - 它的事件处理程序将被执行,而不是引发事件的域方法。

该事件包含更新域模型所需的所有内容(并将更新应用于读取模型)。执行的域方法可以让您发现可以引发事件。

我希望这会有所帮助。如果我需要提供更多信息,请告诉我。

祝你好运!!