引发领域事件时,谁负责实体的突变? DDD

Who is responsible for entity's mutation when domain event is raised? DDD

我一直在学习 CQRS/ES。查看小型示例项目,我经常看到 事件改变实体状态 。例如,如果我们查看 Order 聚合根 :

public class Order : AggregateRoot {
    private void Apply(OrderLineAddedEvent @event) {
        var existingLine = this.OrderLines.FirstOrDefault(
            i => i.ProductId == @event.ProductId);

        if(existingLine != null) {
            existingLine.AddToQuantity(@event.Quantity);
            return;
        }

        this.OrderLines.Add(new OrderLine(@event.ProductId, @event.ProductTitle, @event.PricePerUnit, @event.Quantity));
    }

    public ICollection<OrderLine> OrderLines { get; private set; }

    public void AddOrderLine(/*parameters*/) {
        this.Apply(new OrderLineAddedEvent(/*parameters*/));
    }

    public Order() {
        this.OrderLines = new List<OrderLine>();
    }

    public Order(IEnumerable<IEvent> history) {
        foreach(IEvent @event in history) {
            this.ApplyChange(@event, false);
        }
    }
}

public abstract class AggregateRoot  {
    public Queue<IEvent> UncommittedEvents { get; protected set; }

    protected abstract void Apply(IEvent @event);

    public void CommitEvents() { 
        this.UncommittedEvents.Clear();
    }

    protected void ApplyChange(IEvent @event, Boolean isNew) {
        Apply(@event);
        if(isNew) this.UncommittedEvents.Enqueue(@event);
    }
}

当应用 OrderLineAddedEvent 时,它会通过添加新订单行来改变 Order。但是我不明白这些东西:

实体不会神奇地自我更新。 Something(通常是服务)会调用实体的更新行为。因此,服务使用将生成和应用事件的实体,然后服务将通过存储库保存实体,然后从实体获取新事件并发布它们。

另一种方法是事件存储本身发布事件。

事件溯源是关于将实体状态表示为事件流,这就是实体通过生成和应用事件来更新自身的原因,它需要 create/add 对事件流的更改。该流也是它存储在数据库中的内容,也就是事件存储。

我还在试验 ES,所以这仍然是一种意见,而不是任何指导:)

在某个阶段,我遇到了 Jan Kronquist 的 post:http://www.jayway.com/2013/06/20/dont-publish-domain-events-return-them/

要点是事件应该从域返回,而不是从域内发送。这真的引起了我的共鸣。

如果采用一种更传统的方法,其中使用正常的面向持久性的存储库,应用层将处理事务和存储库访问。将简单地调用该域来执行该行为。

还有,领域应该始终坚持执着无明。让聚合根维护事件列表对我来说总是有些奇怪,我绝对不喜欢让我的 ARs 从一些公共基础继承。感觉不够干净

因此,使用您所拥有的将其组合在一起:

public OrderLineAddedEvent AddOrderLine(/*parameters*/) {
    return this.Apply(new OrderLineAddedEvent(/*parameters*/));
}

在我的 POC 中,我也没有使用 IEvent 标记界面,而只是使用 object.

现在 应用程序层 重新控制了持久性。

我有一个实验性 GitHub 存储库:

我有一段时间没时间看它了,我知道我已经做了一些修改,但欢迎你看一下。

基本思路是 应用层 将使用 EventStore/EventStream 以与应用层 将使用 RepositoryEventStream 将应用于聚合。从域行为返回的所有事件都将添加到 EventStream 中,然后再次持久化。

这会将所有面向持久性的位保留在域之外。

最近我将我的实体分成两个对象。

首先是我所说的文档对象。这主要只是一个状态,ORM class 以及与信息如何持久化相关的所有配置。

然后我用一个 Entity 对象包装那个 Document,它基本上是一个包含所有行为的变异服务。

我的实体基本上是无状态对象,当然除了所包含的文档之外,但无论如何,我主要避免与外界接触。