2011-09-05 36 views
12

我很努力地通过重播来自EventStore的事件来重建模型时发生的事情,特别是当事件可能触发其他事件时。事件源:触发他人和重建状态的事件

例如,已经进行了10次购买的用户应该被推荐给优先顾客并且接收提供他们特定促销的电子邮件。

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

回答

8

事件链可能非常棘手,很容易失控,所以我会尽量避免它。例如,在您描述的情况下,我会提出一个UserPromotedEvent(甚至可能使用PromoteUserCommand),但是我不会将电子邮件的实际/实际发送作为我的域的一部分。相反,我会为UserPromotedEvent创建额外的处理程序/去标准化程序,它将注册发送电子邮件的必要性,并且很可能会进行一些额外的检查。之后,另一个流程将收集尚未处理的电子邮件的信息并发送。这种方法可以缓解不完全可访问/可扩展的电子邮件网关可能出现的问题。

更一般而言 - 事件链接的需要经常表明您应该考虑为该流程实施Saga

2

当您重放事件时,您没有重放生成这些事件的所有域逻辑。通常在你的域名方法中,你会引发一个事件;那么提升该事件应该更新该域对象的整体状态。

例如:

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相同 - 它的事件处理程序将被执行,而不是引发事件的域方法。

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

我希望这会有所帮助。让我知道是否需要提供更多信息。

祝你好运!

6

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

在你的情况,传奇订阅PurchaseMadeEvent和问题PromoteCustomer命令,这导致发生CustomerPromoted事件。再次,有另一个传奇订阅CustomerPromoted事件并发送SendEmailToPromotedCustomer命令。当你正在重播事件时 - 只要不订阅CustomerPromoted事件的传奇。

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

+0

我意识到这是一个非常古老的答案,但是,佐贺如何知道当它收到一个'PurchaseMadeEvent'时发出'PromoteCustomer'命令?这依赖于(根据OP的描述)客户做了10次购买,这是佐贺不应包含的域逻辑。也许总是激发一个'TestToPromoteCustomer'并让聚合体做检查来实际进行升级?这虽然感觉有点笨拙..感谢任何洞察 –

+0

是的,你说的对,传奇应该发送TestToPromoteCustomer命令。我认为为了可维护性而牺牲纯度绝对没问题。 – xelibrion