持久性和域事件具有持久性无知的对象 [英] Persistence and Domain Events with persistence ignorant objects

查看:215
本文介绍了持久性和域事件具有持久性无知的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经在领域驱动设计研究结合域事件的。我真的很喜欢关注这些事件提供的分离。我遇到了一个问题,坚持用一个域对象,提高域名事件的顺序。我想提出事件域对象,但我想他们是无知的持久性。

I've been studying on domain driven design in conjunction with domain events. I really like the separations of concerns those events provide. I ran into an issue with the order of persisting a domain object and raising domain events. I would like to raise events in the domain objects, yet I want them to be persistence ignorant.

我已经创建了一个基本的 ShoppingCartService ,这个结帐方法:

I've created a basic ShoppingCartService, with this Checkout method:

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

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

在这个例子中,订单的构造将提高可通过一定的处理程序进行处理的 OrderCreated 事件。不过,我不想当实体尚未持久或以某种方式持续时未能得到提升的事件。

In this example, the constructor of Order would raise an OrderCreated event which can be handled by certain handlers. However, I don't want those events to be raised when the entity is not yet persisted or when persisting somehow fails.

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

To solve this issue I have figured several solutions:

1。引发事件的服务:

而不是在域对象引发事件的,我可以提高服务的事件。在这种情况下,结帐方法将提高 OrderCreated 事件。这种方法的缺点的是,通过望订单域对象,目前尚不清楚该事件是由什么方法提高。此外,开发人员必须记得在别处创建一个以提高该事件。这感觉不对。



2。队列域的活动

Instead of raising the event in the domain object, I could raise events in the service. In this case, the Checkout method would raise the OrderCreated event. One of the downsides of this approach is that by at looking the Order domain object, it isn't clear which events are raised by what methods. Also, a developer has to remember to raise the event when an order is created elsewhere. It doesn't feel right.


2. Queue domain events

另一种选择是要排队域中的事件,并提高他们坚持成功的时候。这可以通过例如使用语句来实现:

Another option is to queue domain events and raise them when persisting succeeded. This could be achieved by a using statement for example:

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

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

QueueEvents&LT; T&GT; 的方法将设置一个布尔值真正 DomainEvents .Raise&LT; T&GT; 的方法将排队的事件,而不是直接执行它。在 QueueEvent&LT的处置回调; T&GT; ,排队的事件中执行,这可确保持续存在的已经发生了。这似乎是相当棘手的,它需要的服务,了解哪个事件在域对象被提出。在这个例子中我提供它也仅支持一种类型的事件也可以提高,然而,这可以围绕工作。



3。坚持域事件

The QueueEvents<T> method would set a boolean to true and the DomainEvents.Raise<T> method would queue the event rather than executing it directly. In the dispose callback of QueueEvent<T>, the queued events are executed which makes sure that the persisting already happened. This seems rather tricky and it required the service to know which event is being raised in the domain object. In the example I provided it also only supports one type of event to be raised, however, this could be worked around.


3. Persist in domain event

我可以使用域事件持续的对象。这似乎不错,除了一个事实,该事件处理程序持续对象应先执行,但是我读的地方,域中的事件不应该依赖执行的特定顺序。也许这并不重要和域事件可能在某种程度上知道在哪个命令处理程序应该执行。例如:假设我有一个定义域事件的接口的处理的,一个实现应该是这样的:

I could persist the object using a domain event. This seems okay, except for the fact that the event handler persisting the object should execute first, however I read somewhere that domain events should not rely on a specific order of execution. Perhaps that is not that important and domain events could somehow know in which order the handlers should execute. For example: suppose I have an interface defining a domain event handler, an implementation would look like this:

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

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

When I want to handle persisting in using an event handler too, I would create another handler, deriving from the same interface:

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

现在 NotifyCustomer 行为取决于订单被保存在数据库中,因此 PersistOrder 事件处理程序应首先执行。它是可以接受的,这些处理器引入例如属性,指示他们执行的顺序? OrderCreated&GT;从 DomainEvents.Raise&LT执行情况的管理单元()方法:

Now NotifyCustomer behaviour depends on the order being saved in the database, so the PersistOrder event handler should execute first. Is it acceptable that these handlers introduce a property for example that indicates the order of their execution? A snap from the implementation of the 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解决方案得到基本思路正确,但也有更优雅的解决方案,如通过存储库或事件存储发布。举一个例子来看看 SimpleCQRS

Either your (transactional) event handlers enlist in the (potentially distributed) transaction, or you publish/handle the events after the transaction committed. Your "QueueEvents" solution gets the basic idea right, but there are more elegant solutions, like publishing via the repository or the event store. For an example have a look at SimpleCQRS

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

You might also find these questions and answers useful:

<一个href=\"http://stackoverflow.com/questions/13488982/cqrs-storing-events-and-publishing-them-how-do-i-do-this-in-a-safe-way/13490358#13490358\">CQRS:存储事件和发布他们 - ?我怎么在一个安全的方式做到这一点

<一个href=\"http://stackoverflow.com/questions/18404086/event-aggregator-error-handling-with-rollback/18404716#18404716\">Event聚合错误处理通过滚动

这3点更新:

...但是,我读的地方,域中的事件不应该依赖执行的特定顺序。

... however I read somewhere that domain events should not rely on a specific order of execution.

不管你的坚持,事件的顺序绝对事项(合计内)的方式。

Regardless of your way of persisting, the order of events absolutely matters (within an aggregate).

现在NotifyCustomer行为取决于被保存在数据库中的顺序的,因此PersistOrder事件处理程序应首先执行。它是可以接受的,这些处理器引入例如属性,指示他们执行的顺序?

Now NotifyCustomer behaviour depends on the order being saved in the database, so the PersistOrder event handler should execute first. Is it acceptable that these handlers introduce a property for example that indicates the order of their execution?

坚持的和的处理的事件是独立的顾虑 - 使用事件处理程序不存在。一是坚持,再处理。

Persisting and handling events are separate concerns - don't persist using an event handler. First persist, then handle.

这篇关于持久性和域事件具有持久性无知的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆