You need to enable JavaScript to run this app. DDD多聚合根交互处理咨询:路由应用的Request与Route建模
优惠活动
大模型
产品
解决方案
定价
更多

DDD多聚合根交互处理咨询:路由应用的Request与Route建模

跨Aggregate逻辑归属与多上下文实体处理

通用规则澄清

  • 跨Aggregate的同事务修改需求,不应该直接硬写在Domain Service里拉两个AR操作。Domain Service仅承载不属于任何单一AR的纯领域逻辑,遇到跨AR一致性需求,优先判断边界是否划分错误,实在无法拆到同一AR内的,优先用最终一致性方案,不要默认追求强事务跨AR。
  • 不同Bounded Context下的同类实体,本来就应该独立建模,不存在“数据冗余浪费”的问题。每个上下文内的实体只承载当前场景需要的属性和规则,比如职位看板上下文里的职位实体,只需要存储职位ID、展示名称、排序权重即可,不需要携带职位本身的招聘流程、薪资结构等其他上下文的属性,这正是限界上下文的核心设计思路,并非重复开发。
路由业务的落地方案

纠正Aggregate划分的认知误区

之前纠结的高阶Aggregate设计存在概念误解:高阶Aggregate从未要求每次操作都加载全量关联数据,也不要求聚合边界内的所有关联对象都必须随AR一起加载。
判定聚合边界的核心标准非常简单:哪些对象的状态修改,必须保证不存在不一致的中间状态。结合当前业务场景,可以重新调整聚合边界:

  • 把Request作为独立AR:它的基础状态流转(待响应、已取消、爽约)只需要自身规则校验即可,不需要等待Route的状态确认,不要把Route下的所有Request都塞进Route的聚合边界。
  • 把Route作为独立AR:它自身的状态(待调度、已调度、行驶中、已完成)、内部结构(站点排序、有效载荷关联关系)、外部路由引擎计算结果,都属于Route AR的管控范围。Route AR内部不需要加载每个Request的全量属性,仅存储有效载荷和requestId的关联关系即可,Request的具体状态管控属于Request AR的职责。
  • 不要把Routing(外部路由计算结果)作为独立AR:路由结果完全依附于Route存在,没有独立的生命周期和业务规则,Route删除时路由结果同步删除即可,直接作为值对象存在Route的文档结构中,无需单独建集合。

核心用例的逻辑落地

这种边界划分下,完全不需要在单事务中修改多个AR,用领域事件实现最终一致性即可:

  1. Request未被路由时取消:直接加载Request AR,执行自身取消规则标记状态,不涉及其他AR。
  2. Request已被路由、Route已调度时取消:
    • 加载Request AR,校验状态后执行取消标记,和领域事件写入同一个本地事务提交
    • 发布RequestCancelled事件
    • 应用层事件处理器收到事件后,加载对应Route AR,根据requestId找到对应有效载荷,执行移除有效载荷、清理仅关联单个载荷的站点的操作;结构调整完成后调用外部路由引擎重新计算,把新的路由结果更新到Route AR中
    • 不追求Request修改和Route修改的强事务一致性,通过事件表的重试机制保证最终一致,业务上可接受的短时间中间态不影响体验。
  3. Request已被路由、Route行驶中时取消:
    • 加载Request AR,标记状态为爽约,同步写入RequestMarkedAsNoShow事件
    • 事件处理器加载对应Route AR,把关联的有效载荷标记为爽约状态,完成Route内部统计调整即可,无需重新调用外部引擎计算。
  4. Route调度完成后启动:
    • 加载Route AR,把状态从已调度修改为行驶中,同步写入RouteStarted事件
    • 事件处理器遍历Route下关联的所有requestId,批量加载对应Request AR,把Request状态标记为已匹配,无需为了同步修改Request就把所有Request塞进Route的聚合边界。

调整后的Route聚合结构示例

class RouteAggregate {
  private routeId: string;
  private status: 'pending' | 'scheduled' | 'in_progress' | 'completed';
  private stops: Array<{
    stopId: string;
    sequence: number;
    payloads: Array<{
      payloadId: string;
      requestId: string; // 仅存ID引用,不加载Request全量实体
      status: 'active' | 'cancelled' | 'no_show';
    }>
  }>;
  private routingResult: RoutingResult; // 依附Route存在的值对象
}

这种结构下,操作单个Request时直接加载Request AR,无需拉取Route全量数据;调整Route结构时直接加载Route AR,无需拉取所有关联Request的全量属性,完全解决之前“无法加载全量高阶AR”的问题。

内容的提问来源于stack exchange,提问作者rage77

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.27 02:54:03