第二章:聚合根与仓储映射

聚合根(Aggregate Root)是领域驱动设计中一致性边界的关键载体,它决定了仓储(Repository)接口的粒度与访问模式。实体(Entity)与值对象(Value Object)的区分直接影响了持久化策略和信任链路的建立。本章围绕聚合根的边界定义、仓储接口的设计原则以及实体与值对象的映射关系展开,明确各层之间的职责划分与数据流向。

核心要点:仓储接口的粒度应以聚合根为单位,而非单个实体表。值对象应作为聚合根内部状态的一部分进行持久化,不单独暴露仓储接口。

2.1 边界与分层

在典型的 Repository 架构中,领域层与基础设施层之间存在明确的水平边界。聚合根是领域层中的一致性边界,而仓储接口则定义在领域层,其实现位于基础设施层。这一分层确保了领域模型的纯净性——领域层不依赖于任何持久化细节。

层级 包含组件 职责 对仓储的依赖
领域层 聚合根、实体、值对象、仓储接口 表达业务逻辑与规则 依赖接口抽象
应用层 应用服务、DTO 编排领域对象,协调用例 通过依赖注入获取仓储实现
基础设施层 仓储实现、ORM映射、数据库连接 提供技术性持久化能力 实现领域层定义的接口
边界策略:聚合根内部的实体与值对象不允许被外部对象直接引用。外部对象只能通过聚合根实例访问其内部子实体,这种访问路径形成了数据流的唯一入口。

2.2 组件职责与映射关系

实体拥有唯一标识(ID),其状态在整个生命周期内可以发生变化;值对象没有固有标识,由属性值定义其相等性。聚合根作为根实体,持有对内部实体和值对象的引用,并负责维护整个一致性边界内的业务规则。

仓储接口的粒度定义为聚合根级别:

  • 粗粒度接口:Repository<Order, OrderId> 可操作整个订单聚合,包括订单项(实体)和收货地址(值对象)。
  • 细粒度接口(禁止):OrderItemRepository 或 AddressRepository,这会破坏聚合边界,导致外部直接操控内部状态。

2.3 数据流与控制流

在典型的数据查询与持久化场景中,数据流遵循以下路径:

  1. 应用层调用仓储接口的 save(aggregate) 或 findById(id) 方法。
  2. 仓储实现(Infrastructure)将聚合根拆解为对应的数据库表行。
  3. 值对象作为聚合根表或子实体表的嵌入式列(嵌入映射),或序列化为 JSON 字段。
  4. 实体映射为独立的数据表行,但其生命周期完全由聚合根控制。

2.4 聚合根与仓储映射架构图

聚合根与仓储映射架构图 领域层(Domain Layer) 聚合根(Aggregate Root) Order(唯一标识 OrderId) 实体(Entity) OrderItem 值对象(VO) Address 仓储接口 IOrderRepository save(Order) / findById(OrderId) 基础设施层(Infrastructure) OrderRepositoryImpl 实现 IOrderRepository 接口 ORM 映射配置 聚合根表 / 子实体表 / 值对象嵌入 数据库 orders / order_items / 嵌入式地址字段 控制流:接口调用 映射规则说明 • 聚合根 => 独立主表(orders) • 实体 => 子表(order_items),外键依赖聚合根 • 值对象 => 嵌入式字段或 JSON 列 信任链路 1. 应用层信任领域层接口契约 2. 基础设施层保证数据一致 3. 聚合根保证业务不变量

2.5 信任链路与选型权衡

信任链路定义了不同层之间的依赖关系与验证承诺:

  • 第一级信任链路:实体内部直接持有值对象的引用,无需通过仓储再次查询。值对象的状态变更由实体内部方法封装。
  • 第二级信任链路:聚合根通过仓储接口与数据库交互,应用层不得直接通过仓储获取聚合根内部的子实体。
  • 第三级信任链路:基础设施层负责将聚合根的状态完整持久化到存储中,保证最终一致性。
选型维度 推荐策略 不推荐策略 风险说明
仓储接口粒度 以聚合根为单位 以实体表为单位 粒度过细会导致事务边界模糊,容易引发一致性问题
值对象持久化 嵌入到聚合根表或子表 独立映射为一张表 独立映射会引入不必要的外键关系,增加复杂性
子实体更新策略 整体替换(整个聚合根更新) 部分更新(仅更新特定子实体) 部分更新可能绕过聚合根的业务规则校验
风险点:如果值对象被多个聚合根共享引用(例如地址对象被多个订单引用),必须考虑值对象是否应提升为实体,否则会出现更新传播不可控的问题。常见解决方案是将共享值对象设计为不可变(Immutable),或在其内部使用版本号进行乐观锁控制。

2.6 落地步骤

在实际项目中引入聚合根与仓储映射时,建议按以下步骤执行:

  1. 识别聚合边界:与领域专家协作,明确哪些实体与值对象属于同一个业务一致性边界。
  2. 定义聚合根:选择边界内具有全局唯一标识的实体作为聚合根,将所有外部访问路径限定在聚合根上。
  3. 区分实体与值对象:根据是否拥有独立标识、是否可变、相等性判断标准进行分类。
  4. 设计仓储接口:每个聚合根只对应一个仓储接口,接口方法仅操作聚合根级别,不接受子实体类型作为参数。
  5. 实现持久化映射:在基础设施层配置 ORM 映射,将子实体映射为关联表,值对象映射为嵌入式组件。
  6. 编写集成测试:验证聚合根的整体保存与重建是否完整,值对象是否被正确加载。
落地建议:可以先用一个简单的聚合根(如用户和地址)进行试点,确认映射机制稳定后再推广到复杂聚合中。同时,保持值对象的不可变性有助于减少缓存刷新和并发冲突。

2.7 验收标准

验收项 检查方式 通过条件
聚合根边界完整性 代码审查 外部代码无法直接访问聚合根内部的实体集合
仓储接口粒度 接口方法检查 所有仓储方法参数与返回值均为聚合根类型
值对象持久化 数据库表结构检查 值对象未出现独立数据表或独立仓储
一致性保障 集成测试 多次保存与加载聚合根,状态完全一致
信任链路 应用层调用路径检查 应用层仅通过聚合根实例访问子实体,未绕过仓储直接操作

通过以上设计,聚合根成为数据层的核心守卫,仓储接口成为领域层与基础设施层之间唯一且安全的泵。这种映射关系为后续的多数据库支持、缓存策略和事件溯源打下了坚实的基础。