6

我一直在研究域驱动设计与domain events。我真的很喜欢这些事件提供的分离关注点。我遇到了一个持久化域对象和引发域事件的问题。我想在域对象中引发事件,但我希望它们是持久性的无知。持久性和域名事件与持久性的无知对象

我已经创建了一个基本的ShoppingCartService,用这种方法Checkout

public void Checkout(IEnumerable<ShoppingCartItem> cart, Customer customer) 
{ 
    var order = new Order(cart, customer); 

    _orderRepositorty.Add(order); 
    _unitOfWork.Commit(); 
} 

在这个例子中,Order构造函数将引发OrderCreated事件可以通过一定的处理程序进行处理。但是,我不希望在实体未持续存在或持续存在失败时提出这些事件。

为了解决这个问题,我已经找到了几种解决方案:在服务

1.引发事件:

而不是在域对象引发事件,我可以提高在服务事件。在这种情况下,Checkout方法会引发OrderCreated事件。这种方法的缺点之一是,通过查看域对象,不清楚哪些事件是由什么方法引发的。另外,开发人员必须记得在其他地方创建订单时提出该事件。它感觉不对。


2.队列域事件

另一种选择是要排队域事件,并提高他们坚持成功的时候。这可能是由using声明例如可以实现:

using (DomainEvents.QueueEvents<OrderCreated>()) 
{ 
    var order = new Order(cart, customer); 

    _orderRepositorty.Add(order); 
    _unitOfWork.Commit(); 
} 

QueueEvents<T>方法将一个boolean值设置为trueDomainEvents.Raise<T>方法将排队的事件,而不是直接执行它。在QueueEvent<T>的处置回调中,排队的事件被执行,以确保持续已经发生。这似乎相当棘手,它需要服务知道在域对象中引发哪个事件。在我提供的例子中,它也只支持一种类型的事件被提出,但是,这可以被解决。


3.坚持域事件

我可以使用域事件持续的对象。这似乎没问题,除了事件处理程序持久化对象应该先执行,但是我在某处读取域事件不应该依赖于特定的执行顺序。也许这并不重要,域名事件可能会以某种方式知道处理程序应该以何种顺序执行。例如:假设我有定义域事件处理接口,一个实现应该是这样的:

public class NotifyCustomer : IDomainEventHandler<OrderCreated> 
{ 
    public void Handle(OrderCreated args) 
    { 
     // ... 
    } 
} 

当我想以处理使用事件处理程序过于坚持,我会创造另一个处理程序,推导从相同的接口:

public class PersistOrder : IDomainEventHandler<OrderCreated> 
    { 
     public void Handle(OrderCreated args) 
     { 
      // ... 
     } 
    } 
} 

现在NotifyCustomer行为取决于被保存在数据库中的顺序,所以PersistOrder事件处理程序应首先执行。这些处理程序是否可以引入一个属性来表示它们的执行顺序?从DomainEvents.Raise<OrderCreated>()方法的实现一卡:

foreach (var handler in Container.ResolveAll<IDomainEventHandler<OrderCreated>>().OrderBy(h => h.Order)) 
{ 
    handler.Handle(args); 
} 


现在的问题是,我有什么其他选择?我错过了什么吗?你对我提出的解决方案有什么看法?

+0

您是否考虑过使用某种工厂或工厂方法创建新订单?这将标示实例化订单对象和“创建新订单”之间的显式差异。 – tuespetre

回答

6

您的(事务性)事件处理程序在(可能分布的)事务中登记,或者在事务提交后发布/处理事件。你的“QueueEvents”解决方案的基本思路是正确的,但有更多优雅的解决方案,比如通过存储库或事件存储进行发布。举一个例子来看看

你也可以找到有用的这些问题和答案:

CQRS: Storing events and publishing them - how do I do this in a safe way?

Event Aggregator Error Handling With Rollback


更新于3点:

......但是我在某处看到域名事件d不依赖于特定的执行顺序。

无论你如何坚持,事件的顺序绝对重要(在一个聚合中)。

现在NotifyCustomer的行为取决于保存在数据库中的订单,所以PersistOrder事件处理程序应该先执行。这些处理程序是否可以引入一个属性来表示它们的执行顺序?

坚持处理事件是独立的顾虑 - 不要坚持使用事件处理程序。先坚持,然后处理。

+0

非常感谢您的回答。我已经更新了第3点,因为我认为你混合了升级_events_和执行_event处理程序的顺序。你可以看看吗?提前致谢。 –

+0

我已更新我的答案,希望它有帮助。 –

+0

感谢您的帮助,我想我现在已经明白了。 –