Spring Boot JPA单向一对一共享主键映射保存报错求助
解决Hibernate一对一关联保存时的主键生成错误
问题背景
需要创建两张关联表:
- employee:主表,
id为主键,由Hibernate自动生成 - Address:子表,
address_id作为外键关联employee的id,同时作为自身主键,期望Hibernate自动从employee的主键同步生成该值
保存请求体:
{ "name": "somename", "age": 25, "address": { "address": "Some Address" } }
执行保存操作时触发500内部服务器错误,错误信息:
"message": "ids for this class must be manually assigned before calling save(): com.example.demo.entity.Address; nested exception is org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): com.example.demo.entity.Address"
错误原因
当前实体类的关联配置存在两处关键问题:
Employee类中使用@PrimaryKeyJoinColumn的方式未建立正确的主键同步机制Address类的主键addressId既没有配置自动生成策略,也未关联到Employee的主键,导致Hibernate无法自动生成其主键值
解决方案(共享主键模式)
按照以下方式修改实体类,实现Employee主键自动同步到Address的addressId:
修改Employee.java
@Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name="Employee") public class Employee { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private String name; private int age; // 配置一对一关联,由Address维护关联关系 @OneToOne(cascade = CascadeType.ALL, mappedBy = "employee") private Address address; }
修改Address.java
@Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name="Address") public class Address { @Id private Integer addressId; private String address; // 关联Employee,并复用其主键作为当前实体的主键 @OneToOne @MapsId @JoinColumn(name = "address_id") // 对应数据库Address表的外键列名 private Employee employee; }
配置说明
@MapsId注解:指定使用关联的Employee的主键值来填充当前Address的addressId,实现主键同步cascade = CascadeType.ALL:确保保存Employee时自动级联保存关联的Address- 保存请求时无需手动设置
address.addressId,Hibernate会自动从生成的Employee.id同步赋值
备选方案(Address独立主键)
若需求改为Address拥有独立主键,address_id作为单独的外键列,可使用以下配置:
修改Address.java
@Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name="Address") public class Address { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) // 独立生成主键 private Integer id; private String address; @OneToOne @JoinColumn(name = "address_id") // 外键列关联Employee的id private Employee employee; }
修改Employee.java
@Data @Entity @NoArgsConstructor @AllArgsConstructor @Table(name="Employee") public class Employee { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Integer id; private String name; private int age; @OneToOne(cascade = CascadeType.ALL) @JoinColumn(name = "address_id", referencedColumnName = "id") private Address address; }
注:该方案不符合原需求中“将employee主键作为address的address_id使用”的设定,仅适用于Address需要独立主键的场景。
内容的提问来源于stack exchange,提问作者Thiagarajan Ramanathan
相关产品推荐
相关产品推荐

