You need to enable JavaScript to run this app. DDD:招聘业务场景下需跨聚合引用非根Entity时如何构建Aggregate
优惠活动
大模型
产品
解决方案
定价
更多

DDD:招聘业务场景下需跨聚合引用非根Entity时如何构建Aggregate

核心问题根源

你现在卡壳的本质是对DDD跨聚合引用规则的理解有偏差,完全不需要为了规避规则强行调整已经划分合理的聚合边界。

先澄清跨聚合引用的真实约束

这条规则根本不是说两个聚合之间不能有业务关联,它真正禁止的是:跨聚合持有其他聚合内部非根实体的对象引用(也就是内存里的指针、ORM层直接关联出来的实体对象)。
正确的跨聚合关联方式非常朴素:存对方聚合根的全局唯一ID就行;如果要关联对方聚合内部的非根实体,多存一个这个实体在聚合内部的业务唯一标识就够了,绝对不要直接把整个实体对象拿过来当关联属性。

校验现有聚合划分的合理性

你当前梳理的两个聚合边界,完全踩中了DDD聚合设计的核心要求,根本不需要调整:

  • 以Organisation为根的聚合:根实体持有名下所有JobOffer实体,刚好匹配“Organisation名下有效JobOffer有数量上限”的强一致性规则——这类限额校验必须在同一个聚合的事务里完成,不然并发下很容易超额发布职位;而且JobOffer的生命周期完全依附于Organisation,Organisation注销后,其名下所有JobOffer会同步失效,这个边界划分是正确的。
  • 以Candidate为根的聚合:根实体持有名下所有JobApplication实体,刚好匹配“Candidate名下有效JobApplication有数量上限”的强一致性规则——这类投递限额校验也必须在同一个聚合事务里完成,不然并发下很容易超额投递;而且JobApplication的生命周期完全依附于Candidate,Candidate注销后,其名下所有JobApplication会同步失效,这个边界划分也是正确的。
冲突点的落地解法

你之前的矛盾点,是打算让Candidate聚合内部的JobApplication直接持有JobOffer的对象作为关联属性——但JobOffer是Organisation聚合里的非根实体,这么做当然会触发规则冲突。调整起来非常简单:

  • 移除JobApplication对JobOffer的对象引用,只在JobApplication上新增两个存标识的字段即可:
    • 目标JobOffer所属的Organisation聚合根的全局ID
    • 目标JobOffer在Organisation聚合内部的唯一业务标识
  • 涉及JobOffer有效性的跨聚合校验,不要塞进Candidate聚合内部完成,放到应用层串接流程即可:
    1. 应用层接收到创建JobApplication的请求时,先通过Organisation聚合的仓储,根据传入的JobOffer标识查询对应Organisation聚合,确认目标JobOffer是否存在、是否处于开放可投递的有效状态
    2. 这步校验通过后,再加载Candidate聚合,执行Candidate自身的内部校验——也就是其名下的有效申请数是否超过限额
    3. 所有校验全部通过后,调用Candidate聚合的创建申请方法,把之前拿到的OrganisationID、JobOffer标识传入,生成新的JobApplication实体并落库即可
几个千万别踩的调整坑
  • 不要为了关联方便随意扩大聚合边界:比如想着把JobOffer挪到Candidate聚合里,或是把JobApplication挪到Organisation聚合里——这么做会把两个本来独立的强一致性规则绑定到同一个聚合的事务锁范围内,高并发场景下性能会直接崩溃:比如创建申请时需要锁住整个Organisation的职位列表,同一家公司所有的职位发布、投递接收操作会全部被串行化,根本扛不住正常业务量级。
  • 不要在写模型的聚合里塞入展示用的冗余数据:如果业务需要在申请详情页展示职位名称、公司名称这类信息,全部在查询端的读模型里拼接即可,不要把这些冗余字段塞到写模型的JobApplication实体里,不然时间长了聚合边界会逐渐失效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.23 19:36:04