3

我一直在学习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通过添加新的订单行来改变。但我不明白这些事情:

  • 如果这是一种正确的方法,那么所做的更改如何持续存在?
  • 或者我应该以某种方式将事件发布到相应的处理程序Order?我如何在技术上实现这一点?我应该使用服务总线来传输事件吗?
4

3 回答 3

5

我还在尝试使用 ES,所以这仍然是一种观点,而不是任何指导:)

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

它的要点是事件应该从域返回,而不是从域内分派。这确实引起了我的共鸣。

如果要采用更传统的方法,即使用普通的面向持久性的存储库,应用层将处理事务和存储库访问。只需调用该域来执行该行为。

此外,域应该始终坚持持久性无知。让一个聚合根维护一个事件列表对我来说总是有点奇怪,我绝对不喜欢让我的 AR 继承自一些共同的基础。感觉不够干净。

所以用你所拥有的把它放在一起:

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

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

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

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

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

基本思想是应用层将使用EventStore/EventStream来管理聚合的事件,就像应用层使用Repository. 将EventStream应用于聚合。从域行为返回的所有事件都将被添加到它EventStream之后再次持久化。

这将所有面向持久性的位排除在域之外。

于 2015-02-26T07:16:43.403 回答
3

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

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

事件溯源是将实体状态表示为事件流,这就是实体通过生成和应用事件来更新自身的原因,它需要创建/添加对事件流的更改。该流也是它存储在 db aka Event Store 中的内容。

于 2015-02-25T20:01:28.827 回答
1

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

首先是我所说的 Document 对象。这主要是一个状态,ORM 类具有与信息如何持久化相关的所有配置。

然后我用一个实体对象包装该文档,该对象基本上是一个包含所有行为的变异服务。

我的实体基本上是无状态的对象,当然除了包含的文档,但无论如何,我大多避免暴露于外部世界。

于 2015-11-28T09:38:43.563 回答