Hibernate 6.6:如何正确注解含嵌套集合的实体以实现持久化
问题:Hibernate 6.6中持久化嵌套集合(Map<String, List>和List)
现有实体类
@Entity @Getter public class EntityA { @Id private long id; Map<String, List<EntityB>> map; } @Entity @Getter public class EntityB { @Id private long id; List<EntityB> list; }
遇到的问题
尝试@ElementCollection与@OneToMany的多种组合均失败,即使注释掉EntityB中的List,仍报错:
Basic collection has element type 'EntityB' which is not a known basic type (attribute is not annotated '@ElementCollection', '@OneToMany', or '@ManyToMany')
已知一种通过新增中间类的可行方案,但希望不新增中间类实现需求:
中间类方案代码
public class EntityBList { @Id private long id; @OneToMany private List<EntityB> elements; }
修改EntityA的map:
@ElementCollection @CollectionTable(name = "mapping", joinColumns = { @JoinColumn(name = "entitya_id", referencedColumnName = "id") }) @MapKeyColumn(name = "name") @Column(name = "entityblist") Map<String, EntityBList> map;
修改EntityB的list:
@OneToOne EntityBList list;
解决方案(无需新增中间类)
Hibernate 6.6支持直接映射嵌套集合,无需额外中间实体类,以下是正确的注解配置:
1. 配置EntityA的Map<String, List<EntityB>>
使用@OneToMany结合关联表来维护映射关系,明确标记集合为实体关联:
@Entity @Getter public class EntityA { @Id private long id; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @CollectionTable( name = "entitya_entityb_map", joinColumns = @JoinColumn(name = "entitya_id") ) @MapKeyColumn(name = "map_key") // 存储Map中String键的列名 @JoinColumn(name = "entityb_id") // 关联EntityB的外键列 private Map<String, List<EntityB>> map; }
@CollectionTable定义中间关联表,用于存储EntityA的ID、Map的键值和EntityB的ID@MapKeyColumn指定存储Map键的字段,Hibernate会自动处理List的嵌套存储cascade = CascadeType.ALL和orphanRemoval = true确保集合内的EntityB能被同步持久化、更新和删除
2. 配置EntityB的自关联List<EntityB>
这是典型的自关联一对多关系,直接用@OneToMany结合外键字段实现:
@Entity @Getter public class EntityB { @Id private long id; @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true) @JoinColumn(name = "parent_entityb_id") // 存储父EntityB ID的外键列 private List<EntityB> list; }
@JoinColumn指定子EntityB关联父EntityB的外键字段,无需额外关联表,直接在EntityB表中添加parent_entityb_id字段即可
关键说明
- 之前的报错是因为注解组合未正确标记集合为实体关联,Hibernate将其识别为基础类型集合,上述配置通过
@OneToMany明确了关联关系 - Hibernate 6对嵌套集合的支持大幅优化,无需通过中间类包装List即可直接映射
Map<String, List<Entity>>
内容的提问来源于stack exchange,提问作者AixNPanes
相关产品推荐
相关产品推荐

