DDD带子实体聚合根的创建更新及持久化相关问题咨询
问题解答
1. 关于聚合根构造函数的校验逻辑
你之前的思路混淆了聚合根业务一致性和持久化规则一致性两个边界,不存在对错,只是适用场景不对:
- 聚合根构造函数只需要校验「创建时必须满足的业务规则」,放到你的场景里,只要校验传入的编号是合法有效的就可以,不需要校验订单项、其他关联属性是否存在
- 持久化规则是只有当订单要落库时才需要满足的规则,和聚合根的初始化逻辑无关,草稿态的订单本身就是业务允许存在的,完全可以合法初始化
2. 持久化校验的放置位置
优先放在聚合根内部,你提到的IsValidToPersist()方案是最优解:
- 所有和订单持久化相关的规则(至少有1个订单项、必填关联属性非空等)都是订单的固有业务规则,放在聚合根内部符合高内聚要求
- 应用服务在调用持久化逻辑前,先调用该方法做校验,不通过直接返回业务错误,不需要把规则散落到应用服务或者Repository层
- Repository层只负责基础的数据库读写,不要放任何业务校验逻辑
3. 应用服务的拆分方案
你提到的拆分思路完全合理,非常适配当前的分步引导场景:
CreateOrderService:校验用户输入的编号合法,创建草稿态订单存入缓存AddOrderLineService/UpdateOrderLineService/RemoveOrderLineService:处理订单项的增改删操作,更新缓存中的订单实例SaveOrderService:校验订单可持久化,执行落库逻辑
不要把所有逻辑塞到同一个AddOrderService里,会导致逻辑过重,也无法适配多步骤操作、随时跳转的需求。
4. 订单项更新的方案选择
优先选择单独的子操作服务,不要用统一的全量更新服务:
- 单独服务对应独立的用户操作,逻辑更清晰,不需要处理全量替换订单项带来的变更比对成本
- 你当前的草稿订单存在缓存中,每次订单项操作只需要更新缓存实例即可,不需要每次都执行持久化,完全不存在性能损耗的问题
5. 核心疑问:为子实体提供单独服务是否合理
只要满足所有子实体操作必须通过聚合根执行的前提,就是完全合理的:
- 单独的服务只是操作入口的封装,内部逻辑必须是先获取到
Order聚合根实例,再调用聚合根提供的AddOrderLine/UpdateOrderLine等方法操作子实体,绝对不能绕开聚合根直接修改OrderLine - 这种设计既保证了聚合根的封装性,又能适配你分步操作、灵活修改的业务需求
内容的提问来源于stack exchange,提问作者Jaime
相关产品推荐
相关产品推荐

