我一直在研究领域驱动设计领域事件 http://www.udidahan.com/2009/06/14/domain-events-salvation/。我真的很喜欢这些事件提供的关注点分离。我遇到了保留域对象和引发域事件的顺序问题。我想在域对象中引发事件,但我希望它们对持久性一无所知。
我已经创建了一个基本的ShoppingCartService
, 有了这个Checkout
method:
public void Checkout(IEnumerable<ShoppingCartItem> cart, Customer customer)
{
var order = new Order(cart, customer);
_orderRepositorty.Add(order);
_unitOfWork.Commit();
}
在这个例子中,构造函数Order
会提出一个OrderCreated
可以由某些处理程序处理的事件。但是,我不希望在实体尚未持久化或持久化失败时引发这些事件。
为了解决这个问题我想了几个解决方案:
1. 在服务中引发事件:
我可以在服务中引发事件,而不是在域对象中引发事件。在这种情况下,Checkout
方法会提高OrderCreated
事件。这种方法的缺点之一是,通过查看Order
域对象,不清楚哪些事件是由哪些方法引发的。此外,开发人员必须记住在其他地方创建订单时引发该事件。感觉不对。
2. Queue domain events
另一种选择是将域事件排队并在持久成功时引发它们。这可以通过以下方式实现using
声明例如:
using (DomainEvents.QueueEvents<OrderCreated>())
{
var order = new Order(cart, customer);
_orderRepositorty.Add(order);
_unitOfWork.Commit();
}
The QueueEvents<T>
方法将设置一个布尔值true
和DomainEvents.Raise<T>
方法会将事件排队,而不是直接执行它。在dispose回调中QueueEvent<T>
,执行排队的事件,确保持久化事件已经发生。这看起来相当棘手,它需要服务知道域对象中正在引发哪个事件。在我提供的示例中,它也仅支持引发一种类型的事件,但是,这可以解决。
3. Persist in domain event
我可以使用域事件来持久化该对象。这看起来没问题,除了保存对象的事件处理程序应该首先执行这一事实之外,但是我在某处读到域事件不应依赖于特定的执行顺序。也许这并不那么重要,域事件可以以某种方式知道处理程序应该执行的顺序。例如:假设我有一个定义域事件的接口handler,一个实现将如下所示:
public class NotifyCustomer : IDomainEventHandler<OrderCreated>
{
public void Handle(OrderCreated args)
{
// ...
}
}
当我也想使用事件处理程序来处理持久化时,我会创建另一个处理程序,派生自相同的接口:
public class PersistOrder : IDomainEventHandler<OrderCreated>
{
public void Handle(OrderCreated args)
{
// ...
}
}
}
Now NotifyCustomer
行为取决于数据库中保存的顺序,因此PersistOrder
事件处理程序应该首先执行。这些处理程序引入一个属性(例如指示其执行顺序)是否可以接受?实施的快照DomainEvents.Raise<OrderCreated>()
method:
foreach (var handler in Container.ResolveAll<IDomainEventHandler<OrderCreated>>().OrderBy(h => h.Order))
{
handler.Handle(args);
}
Now my question is, do I have any other options? Am I missing something? And what do you think of the solutions I proposed?