如何在CQRS中处理基于集合的一致性验证?

时间:2010-05-26 21:18:14

标签: validation domain-driven-design cqrs eventual-consistency

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

  1. Facility必须有一个唯一的名称。
  2. 由于我在查询端使用最终一致的数据库,因此在事件处理或处理事件时,其中的数据不能保证准确。

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

4 个答案:

答案 0 :(得分:18)

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

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

答案 1 :(得分:4)

Eventual Consistency and Set Validation概述了三种方法:

  1. 如果问题很少或不重要,请以管理方式处理,可能是向管理员发送通知。
  2. 发送DuplicateFacilityNameDetected事件,这可能会启动自动解决过程。
  3. 维护一个了解已使用的Facility名称的服务,可能是通过监听域事件并维护一个持久的名称列表。在创建任何新设施之前,请先检查此服务。
  4. 另请参阅此相关问题:Uniqueness validation when using CQRS and Event sourcing

答案 2 :(得分:1)

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

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

显然,当命令包含主键检查表中不存在的值时,操作成功。

主键约束表应仅用作服务,但是,由于您实现了事件源,您可以重放事件以重建主键约束表。

答案 3 :(得分:0)

由于唯一性检查将在数据写入之前完成,因此更好的方法是构建事件跟踪服务,该服务将在流程完成或终止时发送通知。