33

我有一个相当简单的域模型,涉及Facility聚合根列表。鉴于我使用 CQRS 和事件总线来处理从域引发的事件,您如何处理集合验证?例如,假设我有以下要求:

  1. Facility's 必须有一个唯一的名称。

由于我在查询端使用最终一致的数据库,因此不能保证其中的数据在事件处理器处理事件时是准确的。

例如,aFacilityCreatedEvent在查询数据库事件处理队列中等待处理并写入数据库。一个新CreateFacilityCommand的被发送到要处理的域。域服务查询读取数据库以查看是否有任何其他Facility' 已使用该名称注册,但返回 false 因为CreateNewFacilityEvent尚未处理并写入存储。newCreateFacilityCommand现在将成功并抛出另一个FacilityCreatedEvent,当事件处理器尝试将其写入数据库并发现另一个Facility已使用该名称存在时,它会爆炸。

4

4 回答 4

20

我采用的解决方案是添加一个System可以维护当前Facility名称列表的聚合根。创建新的Facility时,我使用System聚合(只有一个System作为全局对象/单例)作为它的工厂。如果给定的设施名称已经存在,那么它将引发验证错误。

这将验证约束保持在域内,并且不依赖于最终一致的查询存储。

于 2010-06-23T18:25:06.540 回答
6

最终一致性和集合验证中概述了三种方法:

  1. 如果问题很少见或不重要,请以管理方式处理,可能通过向管理员发送通知。
  2. 调度 DuplicateFacilityNameDetected 事件,该事件可以启动自动解决过程。
  3. 维护一个知道使用的设施名称的服务,可能通过侦听域事件并维护名称的持久列表。在创建任何新设施之前,请先检查此服务。

另请参阅此相关问题:Uniqueness validation when using CQRS and Event sourcing

于 2016-05-13T17:55:40.647 回答
2

在这种情况下,您可以实现一个简单的 CRUD 样式服务,该服务基本上在具有主键约束的 Sql 表中执行插入操作。

插入只会发生一次。当本应仅存在一次的具有相同值的重复命令命中聚合时,聚合调用服务,服务因违反主键约束而导致插入操作失败,抛出错误,整个过程失败并且没有事件生成,在查询端没有报告,可能在一个表中报告失败,用于最终的一致性检查,用户可以在其中查询以了解命令处理的状态。要检查这一点,只需使用命令指南一次又一次地查询命令状态视图模型。

显然,当该命令持有一个不存在于主键检查表中的值时,该操作是成功的。

主键约束表只能作为服务使用,但是,因为你实现了事件溯源,你可以重放事件来重建主键约束表。

于 2015-01-17T14:26:53.447 回答
0

因为唯一性检查会在数据写入之前完成,所以更好的方法是构建一个事件跟踪服务,它会在进程完成或终止时发送通知。

于 2016-12-17T02:40:58.377 回答