具有持久性无知对象的持久性和领域事件

2024-05-07

我一直在研究领域驱动设计领域事件 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>方法将设置一个布尔值trueDomainEvents.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?

您的(事务性)事件处理程序参与(可能分布式)事务,或者您在提交事务后发布/处理事件。您的“QueueEvents”解决方案的基本思想是正确的,但还有更优雅的解决方案,例如通过存储库或事件存储进行发布。举个例子看看简单CQRS https://github.com/gregoryyoung/m-r/tree/master/SimpleCQRS

您可能还会发现这些问题和答案很有用:

CQRS:存储事件并发布它们 - 如何以安全的方式执行此操作? https://stackoverflow.com/questions/13488982/cqrs-storing-events-and-publishing-them-how-do-i-do-this-in-a-safe-way/13490358#13490358

带回滚的事件聚合器错误处理 https://stackoverflow.com/questions/18404086/event-aggregator-error-handling-with-rollback/18404716#18404716


第 3 点更新:

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

无论你坚持的方式如何,事件的顺序绝对重要(在聚合内)。

现在,NotifyCustomer 行为取决于数据库中保存的订单,因此应首先执行 PersistOrder 事件处理程序。这些处理程序引入一个属性(例如指示其执行顺序)是否可以接受?

坚持 and handling事件是单独的关注点 - 不要坚持使用事件处理程序。先坚持,再处理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

具有持久性无知对象的持久性和领域事件 的相关文章

随机推荐