2011-04-21 58 views
6

我一直试图在udi dahan描述的一个新项目中实现这个模式。使用域事件模式

我喜欢if的想法,但我不太确定它应该在什么情况下应用(对这个东西来说是新的......)。

例如让我说我有一个事件OnUserCreated。我希望其中一个处理程序向用户发送确认电子邮件。但是如果事件被触发了,电子邮件就会被发送,然后在提交事务时出错,并且数据永远不会保存到数据库中。该模式适用于这种情况吗?我读过人们说不,但我已经做过的一些项目实际上是这样做的。或者这是我应该只用于加载和更新其他实体的东西......另一方面,我读某人说,操作所需的相关实体应该已经加载,所以我不应该从数据库中加载它们事件。

回答

7

这当然取决于你如何选择实现你的系统。

你可以在这里考虑多种选择:

1.两阶段提交 当执行两阶段提交,基本上每个处理器包含3种方法:一个准备,一个承诺和一个卷背部。

对于所有的事件处理程序,Prepare首先被调用。如果这些报告都没有问题,则调用所有处理程序的Commit()方法。如果其中任何一个报告有问题 - 尽管Prepare()调用没有报告问题 - 那么对于已经执行了Commit()的所有处理程序,您可以调用它们的Rollback()方法。

2.内部和外部事件处理程序 另一种选择是使事件处理程序的一个分离。你可以发布一个事件,比如UserCreated,它由事件处理程序首先参与事务处理。事件作为事务的一部分存储在数据库中。然后,您可以拥有仅对已存储在数据库中的事件做出反应的外部事件处理程序 - 例如您的电子邮件发件人。这些只能在初始事务提交后才能调用。

我相信你可以想出更多的方法来处理你的具体情况。

3

使用域事件允许您在业务事务(创建用户)之外移动某些操作(发送电子邮件)。事件的发布与db事务处理相同,所以如果db事务失败,事件将不会被发布。使用持久的消息队列系统(msmq)可确保如果事件已发布,处理程序将最终执行。

你流应该是这个样子:

Begin Transaction 
    Receive Command 
    Call Aggregate Method 
     Publish Events // will only be published if the transaction succedes 
Commit Transaction 

Begin Transaction 
    Receive Event 
    Send Email 
End Transaction 

作为一个侧面说明尝试命名事件,而在“开”的前缀,因为它更容易在句子中使用它们。