JPA中持久化包含父类的列表问题咨询
解决方案说明
首先要明确:你的代码里存在两个核心问题需要先修正,再处理集合的持久化:
1. 修正父类Parent的注解冲突
Parent同时标注@MappedSuperclass和@Embeddable是错误的:
@MappedSuperclass用于给实体子类提供共享的字段映射,本身不能被实例化;@Embeddable是嵌入式组件,属于实体的一部分,不能作为实体类的父类。
因为你的Child1、Child2都是@Entity,所以Parent只需要保留@MappedSuperclass:
@MappedSuperclass public class Parent { String name; // 省略getter/setter、无参构造 }
2. 实体类Entity必须添加主键
JPA要求所有实体类必须有主键字段,否则无法持久化,需要给Entity添加@Id注解的主键:
@Entity @Table(name = "entity_table") public class Entity { // 类名首字母大写,符合Java规范 @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 主键字段 String name; List<Parent> parents; // 省略无参构造、getter/setter }
3. 持久化List<Parent>:不能用@ElementCollection
@ElementCollection仅用于存储嵌入式组件(@Embeddable)或基本类型/字符串的集合,而你的Child1、Child2是独立的@Entity,所以必须用实体间的关联关系,结合多态映射来实现:
方式一:直接通过外键关联(推荐)
利用Child1、Child2中的entityName字段作为外键,关联到Entity的name字段,使用@OneToMany实现多态关联:
@Entity @Table(name = "entity_table") public class Entity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; String name; // 多态关联Parent的子类Child1、Child2 @OneToMany @JoinColumn(name = "entity_name", referencedColumnName = "name") private List<Parent> parents; // 省略无参构造、getter/setter }
方式二:使用中间表(@JoinTable)
如果需要通过中间表关联,注意因为Child1和Child2的主键类型不同(Double和String),中间表的关联字段需要兼容两种类型,这里给出通用示例:
@Entity @Table(name = "entity_table") public class Entity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; String name; @OneToMany @JoinTable( name = "entity_child_link", // 中间表名称 joinColumns = @JoinColumn(name = "entity_name", referencedColumnName = "name"), // 关联Entity的name字段 inverseJoinColumns = @JoinColumn(name = "child_key") // 中间表中存储子类主键的字段,需兼容Double和String类型 ) private List<Parent> parents; // 省略无参构造、getter/setter }
关键说明
- JPA会自动处理多态关联,查询时会从
Child1和Child2表中筛选出entityName匹配的记录,返回包含Child1、Child2实例的List<Parent>; - 必须保证
Entity的name字段唯一,否则会关联到多个实体的子类数据。
内容的提问来源于stack exchange,提问作者Alireza Asgarian
相关产品推荐
相关产品推荐

