JPA OneToMany映射时含部分嵌入主键的子实体parentId为空问题求助
问题根因
你当前配置中Child实体的parent关联字段标记了insertable = false, updatable = false,JPA不会自动将关联Parent的ID同步到子表的parentId字段;而子实体的嵌入主键ChildId中的parentId是独立字段,无主动赋值时默认是空值,因此会抛出主键字段为空的异常。
推荐解决方案
方案1:使用@MapsId注解自动同步父ID(最优选择)
修改Child实体的parent关联配置,添加@MapsId注解绑定嵌入主键的对应字段,去掉insertable、updatable的false限制:
public class Child { @EmbeddedId private ChildId id; private String myCol; @ManyToOne(fetch=FetchType.LAZY) @MapsId("parentId") // 声明该关联对应嵌入主键中的parentId字段 @JoinColumn(name = "parentId") private Parent parent; }
配置完成后原有逻辑无需修改,保存父实体时CascadeType.ALL配置会自动级联保存子实体,JPA会自动将父实体生成的序列ID同步到子实体ChildId的parentId字段,无需手动赋值。
方案2:手动赋值(适用于必须保留原关联字段只读配置的场景)
如果因业务要求必须保留parent字段的insertable = false, updatable = false配置,调整保存逻辑即可:
- 先保存父实体,此时序列会生成ID赋值到父实体的
id字段 - 遍历父实体的
childList,逐个给子实体的嵌入主键赋值父ID:child.getId().setParentId(parent.getId()) - 最后保存子实体/更新父实体即可
注意事项
- 若使用Spring Data JPA,保存父实体后需取save方法返回的持久化状态对象,该对象的ID才是序列生成的有效值
- 确保
ChildId类实现了Serializable接口,且重写了equals和hashCode方法,符合嵌入主键的规范要求
内容的提问来源于stack exchange,提问作者Micho Rizo
相关产品推荐
相关产品推荐

