第二章:聚合根与仓储映射
聚合根(Aggregate Root)是领域驱动设计中一致性边界的关键载体,它决定了仓储(Repository)接口的粒度与访问模式。实体(Entity)与值对象(Value Object)的区分直接影响了持久化策略和信任链路的建立。本章围绕聚合根的边界定义、仓储接口的设计原则以及实体与值对象的映射关系展开,明确各层之间的职责划分与数据流向。
核心要点:仓储接口的粒度应以聚合根为单位,而非单个实体表。值对象应作为聚合根内部状态的一部分进行持久化,不单独暴露仓储接口。
2.1 边界与分层
在典型的 Repository 架构中,领域层与基础设施层之间存在明确的水平边界。聚合根是领域层中的一致性边界,而仓储接口则定义在领域层,其实现位于基础设施层。这一分层确保了领域模型的纯净性——领域层不依赖于任何持久化细节。
| 层级 | 包含组件 | 职责 | 对仓储的依赖 |
|---|---|---|---|
| 领域层 | 聚合根、实体、值对象、仓储接口 | 表达业务逻辑与规则 | 依赖接口抽象 |
| 应用层 | 应用服务、DTO | 编排领域对象,协调用例 | 通过依赖注入获取仓储实现 |
| 基础设施层 | 仓储实现、ORM映射、数据库连接 | 提供技术性持久化能力 | 实现领域层定义的接口 |
边界策略:聚合根内部的实体与值对象不允许被外部对象直接引用。外部对象只能通过聚合根实例访问其内部子实体,这种访问路径形成了数据流的唯一入口。
2.2 组件职责与映射关系
实体拥有唯一标识(ID),其状态在整个生命周期内可以发生变化;值对象没有固有标识,由属性值定义其相等性。聚合根作为根实体,持有对内部实体和值对象的引用,并负责维护整个一致性边界内的业务规则。
仓储接口的粒度定义为聚合根级别:
- 粗粒度接口:
Repository<Order, OrderId>可操作整个订单聚合,包括订单项(实体)和收货地址(值对象)。 - 细粒度接口(禁止):
OrderItemRepository或AddressRepository,这会破坏聚合边界,导致外部直接操控内部状态。
2.3 数据流与控制流
在典型的数据查询与持久化场景中,数据流遵循以下路径:
- 应用层调用仓储接口的
save(aggregate)或findById(id)方法。 - 仓储实现(Infrastructure)将聚合根拆解为对应的数据库表行。
- 值对象作为聚合根表或子实体表的嵌入式列(嵌入映射),或序列化为 JSON 字段。
- 实体映射为独立的数据表行,但其生命周期完全由聚合根控制。
2.4 聚合根与仓储映射架构图
2.5 信任链路与选型权衡
信任链路定义了不同层之间的依赖关系与验证承诺:
- 第一级信任链路:实体内部直接持有值对象的引用,无需通过仓储再次查询。值对象的状态变更由实体内部方法封装。
- 第二级信任链路:聚合根通过仓储接口与数据库交互,应用层不得直接通过仓储获取聚合根内部的子实体。
- 第三级信任链路:基础设施层负责将聚合根的状态完整持久化到存储中,保证最终一致性。
| 选型维度 | 推荐策略 | 不推荐策略 | 风险说明 |
|---|---|---|---|
| 仓储接口粒度 | 以聚合根为单位 | 以实体表为单位 | 粒度过细会导致事务边界模糊,容易引发一致性问题 |
| 值对象持久化 | 嵌入到聚合根表或子表 | 独立映射为一张表 | 独立映射会引入不必要的外键关系,增加复杂性 |
| 子实体更新策略 | 整体替换(整个聚合根更新) | 部分更新(仅更新特定子实体) | 部分更新可能绕过聚合根的业务规则校验 |
风险点:如果值对象被多个聚合根共享引用(例如地址对象被多个订单引用),必须考虑值对象是否应提升为实体,否则会出现更新传播不可控的问题。常见解决方案是将共享值对象设计为不可变(Immutable),或在其内部使用版本号进行乐观锁控制。
2.6 落地步骤
在实际项目中引入聚合根与仓储映射时,建议按以下步骤执行:
- 识别聚合边界:与领域专家协作,明确哪些实体与值对象属于同一个业务一致性边界。
- 定义聚合根:选择边界内具有全局唯一标识的实体作为聚合根,将所有外部访问路径限定在聚合根上。
- 区分实体与值对象:根据是否拥有独立标识、是否可变、相等性判断标准进行分类。
- 设计仓储接口:每个聚合根只对应一个仓储接口,接口方法仅操作聚合根级别,不接受子实体类型作为参数。
- 实现持久化映射:在基础设施层配置 ORM 映射,将子实体映射为关联表,值对象映射为嵌入式组件。
- 编写集成测试:验证聚合根的整体保存与重建是否完整,值对象是否被正确加载。
落地建议:可以先用一个简单的聚合根(如用户和地址)进行试点,确认映射机制稳定后再推广到复杂聚合中。同时,保持值对象的不可变性有助于减少缓存刷新和并发冲突。
2.7 验收标准
| 验收项 | 检查方式 | 通过条件 |
|---|---|---|
| 聚合根边界完整性 | 代码审查 | 外部代码无法直接访问聚合根内部的实体集合 |
| 仓储接口粒度 | 接口方法检查 | 所有仓储方法参数与返回值均为聚合根类型 |
| 值对象持久化 | 数据库表结构检查 | 值对象未出现独立数据表或独立仓储 |
| 一致性保障 | 集成测试 | 多次保存与加载聚合根,状态完全一致 |
| 信任链路 | 应用层调用路径检查 | 应用层仅通过聚合根实例访问子实体,未绕过仓储直接操作 |
通过以上设计,聚合根成为数据层的核心守卫,仓储接口成为领域层与基础设施层之间唯一且安全的泵。这种映射关系为后续的多数据库支持、缓存策略和事件溯源打下了坚实的基础。