首页 文章

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

提问于
浏览
28

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

  • Facility 必须有一个唯一的名称 .

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

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

4 回答

  • 3

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

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

  • 17

    _1810249中概述了三种方法:

    • 如果问题很少或不重要,可以通过向管理员发送通知来进行管理 .

    • 调度DuplicateFacilityNameDetected事件,该事件可能启动自动解决过程 .

    • 维护一个了解已使用的Facility名称的服务,可能是通过监听域事件并维护一个持久的名称列表 . 在创建任何新设施之前,请先检查此服务 .

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

  • 1

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

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

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

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

  • 0

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

相关问题