使用Spring Data/Hibernate时如何级联持久化带@EmbeddedId的@OneToMany关系
问题根源
JPA无法自动将父实体生成的主键填充到子实体嵌套的嵌入式主键字段中,你当前的mappedBy = "id.parentId"写法仅定义了关联字段指向,没有建立完整的属性映射关系,所以保存时book_id会为空。
解决方案
1. 调整BookTag实体映射
添加Book关联属性,搭配@MapsId绑定复合主键中的parentId字段:
@Entity @Table(name = "book_tag") @AttributeOverride(name = "parentId", column = @Column(name = "book_id")) public class BookTag extends Tag { @ManyToOne @MapsId("parentId") // 关联TagId中的parentId字段 @JoinColumn(name = "book_id", insertable = false, updatable = false) // 避免与@AttributeOverride的字段定义冲突 private Book book; // 其他属性、getter、setter }
2. 修改Book实体的关联配置
将@OneToMany的mappedBy指向新添加的book属性:
@Entity @Table(name = "book") public class Book { @Id @GeneratedValue @Column(columnDefinition = "BINARY(16)") private UUID id; // 其他属性 @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL, mappedBy = "book") private List<BookTag> tags; // getter、setter }
3. 保存前手动建立双向关联
仅将BookTag添加到Book的tags集合不足以触发关联字段填充,需要给每个BookTag设置所属的Book实例:
// 业务代码示例 Book book = new Book(); // 填充book其他属性 // 构造标签 BookTag tag1 = new BookTag(); TagId id1 = new TagId(); id1.setValue("科幻"); tag1.setId(id1); tag1.setBook(book); // 关键:绑定所属Book实例 BookTag tag2 = new BookTag(); TagId id2 = new TagId(); id2.setValue("畅销"); tag2.setId(id2); tag2.setBook(book); // 绑定所属Book实例 book.setTags(List.of(tag1, tag2)); bookRepository.save(book);
常见错误说明
- 直接用
@JoinColumn代替mappedBy:仅能实现单向关联,仍无法自动填充复合主键中的parentId @MapsId配置错误:未指定对应的复合主键字段名、未设置insertable = false, updatable = false导致字段重复映射报错- 给
parentId加@GeneratedValue:parentId是父实体的主键,无需自主生成,该配置完全无效
内容的提问来源于stack exchange,提问作者Sayago
相关产品推荐
相关产品推荐

