插入带@EmbeddedID子实体的新增父实体时触发IdentifierGenerationException
错误根因
- 双向关联未正确维护:ParentA的children集合中加入Child实体后,没有同步给Child的parentA字段赋值ParentA实例,Hibernate级联保存Child时发现parentA属性为null,无法填充复合主键的parentAId字段。
- 关联逻辑不符合规范:新增Child时需要提前绑定已存在的ParentB实例,否则也会导致复合主键的parentBId字段缺失。
修复方案
步骤1:调整业务保存逻辑
按照如下方式绑定双向关联即可解决问题:
@Transactional public ParentA saveParentAndChild(Long existParentBId, ParentA newParentA, Child newChild) { // 先查询已持久化的ParentB实例 ParentB parentB = parentBRepository.findById(existParentBId) .orElseThrow(() -> new RuntimeException("指定ParentB不存在")); // 绑定双向关联 newChild.setParentA(newParentA); newChild.setParentB(parentB); Set<Child> childSet = new HashSet<>(); childSet.add(newChild); newParentA.setChildren(childSet); // 保存ParentA会自动级联保存关联的Child return parentARepository.save(newParentA); }
步骤2:可选优化(简化关联维护)
可以在ParentA实体中封装关联维护方法,避免每次手动处理双向绑定:
// 在ParentA类中添加以下工具方法 public void addChild(Child child) { if (this.children == null) { this.children = new HashSet<>(); } this.children.add(child); child.setParentA(this); }
后续业务代码调用parentA.addChild(child)即可完成双向关联绑定。
注意事项
- 不需要手动给Child的嵌入式主键ChildPK赋值,
@MapsId注解会自动从关联的ParentA、ParentB实例中获取ID填充主键字段,手动赋值反而会引发主键冲突。 - 确保事务注解正常生效,Spring Data JPA的
save方法执行后,数据库生成的自增ID会自动回写到ParentA实例中,级联保存Child时就能正常读取到该ID。
内容的提问来源于stack exchange,提问作者Enrique Avila
相关产品推荐
相关产品推荐

