如何使用字符串列作为键映射JPA @OneToMany关联关系
JPA 字符串列作为外键关联@OneToMany配置方案
首先先停掉框架自动修改表结构的配置,避免改动存量库:
- 在配置文件中将Hibernate的DDL自动执行参数设为
none:- SpringBoot环境配置:
spring.jpa.hibernate.ddl-auto=none - 原生Hibernate环境配置:
hibernate.hbm2ddl.auto=none
- SpringBoot环境配置:
你之前运行时自动生成student_id列,核心原因是两个配置错误:一是@JoinColumn指定的列名和实际存量表的列不匹配,二是没有明确告诉框架关联键引用的是学生表的字符串类型name字段,框架默认按主键id关联,找不到对应列就自动建列。
正确的实体配置如下,注意修正原有代码里的语法问题:class是Java保留关键字,不能用来做类名和属性名,调整为合法命名即可。
@Entity public class Student { // 原有表的主键字段按实际定义即可,如果name本身就是主键就把@Id加在name上 // 如果主键是其他字段,给name字段加@Column(unique = true)标记唯一即可,非主键列也可以作为关联键 @Id private String id; @Column(unique = true) private String name; private String phone; private String email; // mappedBy的值和多方实体中关联Student的属性名保持一致,属性名不要用class关键字 @OneToMany(mappedBy = "student") private List<SchoolClass> classList = new ArrayList<>(); // 省略构造方法、getter、setter }
@Entity // class是SQL保留关键字,明确指定表名避免SQL执行报错 @Table(name = "class") public class SchoolClass { // 按class表的实际主键定义即可,比如自增id、复合主键都可以 @Id private Long id; private LocalDate date; private String discipline; @ManyToOne // 核心配置: // name = 当前class表中存储学生name值的字符串列名,按实际场景就是"name" // referencedColumnName = 关联的Student表中对应字段的列名,也就是"name" // insertable、updatable设为false,避免JPA维护关联关系时覆盖该列原有值 @JoinColumn(name = "name", referencedColumnName = "name", insertable = false, updatable = false) private Student student; // 省略构造方法、getter、setter }
配置注意事项
- JPA本身完全支持非主键字段作为关联键,唯一要求是被引用的列(也就是学生表的
name列)必须有唯一约束,否则关联查询时会出现结果重复的问题。 - 不要在配置里开启自动DDL,所有表结构变动都手动控制,完全不会影响现有的SQL Server存量数据。
- 如果class表的
name列本身是用来存储班级名称、同时又存学生姓名做关联,属于业务层面的设计问题,在不修改表结构的前提下,加insertable = false, updatable = false可以避免JPA操作时误改该列数据。
内容的提问来源于stack exchange,提问作者Wesley Oliveira Penachia
相关产品推荐
相关产品推荐

