引发领域事件时,谁负责实体的突变? 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
。但是我不明白这些东西:
- 如果这是正确的方法,那么所做的更改如何持久化?
- 或者我应该以某种方式将事件发布到
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
以与应用层 将使用 Repository
。 EventStream
将应用于聚合。从域行为返回的所有事件都将添加到 EventStream
中,然后再次持久化。
这会将所有面向持久性的位保留在域之外。
最近我将我的实体分成两个对象。
首先是我所说的文档对象。这主要只是一个状态,ORM class 以及与信息如何持久化相关的所有配置。
然后我用一个 Entity 对象包装那个 Document,它基本上是一个包含所有行为的变异服务。
我的实体基本上是无状态对象,当然除了所包含的文档之外,但无论如何,我主要避免与外界接触。
我一直在学习 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
的相应处理程序吗?我如何在技术上实现这一点?我应该使用服务总线来传输事件吗?
实体不会神奇地自我更新。 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
以与应用层 将使用 Repository
。 EventStream
将应用于聚合。从域行为返回的所有事件都将添加到 EventStream
中,然后再次持久化。
这会将所有面向持久性的位保留在域之外。
最近我将我的实体分成两个对象。
首先是我所说的文档对象。这主要只是一个状态,ORM class 以及与信息如何持久化相关的所有配置。
然后我用一个 Entity 对象包装那个 Document,它基本上是一个包含所有行为的变异服务。
我的实体基本上是无状态对象,当然除了所包含的文档之外,但无论如何,我主要避免与外界接触。