JPA/Hibernate/SpringBoot中@OneToMany关联实体插入报错如何解决?
问题根因
- EmployeeLocation作为独立
@Entity实体,你将employee_id设为主键,但既没有配置主键生成策略,保存时也没有手动赋值,Hibernate无法获取主键值因此抛出异常。 - 双向关联配置冲突:EmployeeLocation的
@ManyToOne注解上配置了insertable = false, updatable = false,会导致外键字段无法被自动回填,同时父类@OneToMany直接配置@JoinColumn也会和子类的关联配置冲突,增加维护成本。
解决方案
根据你的业务场景可选以下两种方案:
方案1:一个员工对应多个地址(匹配你现有List集合定义)
你需要给employee_location表新增独立主键,调整关联配置:
1. 修改Employee实体
@Entity(name = "employee") class Employee { @Id @Column(name = "id") @GeneratedValue private Long id; // 用mappedBy指向子实体的关联属性,避免重复维护外键 @OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "employee") private List<EmployeeLocation> employeeLocations; // 新增关联维护方法,避免手动设置漏项 public void setEmployeeLocations(List<EmployeeLocation> locations) { this.employeeLocations = locations; locations.forEach(item -> item.setEmployee(this)); } }
2. 修改EmployeeLocation实体
@Entity(name = "employee_location") class EmployeeLocation { // 新增独立主键,配置自增策略 @Id @GeneratedValue private Long id; // 去掉insertable、updatable限制,允许自动填充外键 @ManyToOne @JoinColumn(name = "employee_id", referencedColumnName = "id") private Employee employee; // 其他地址字段... }
3. 保存逻辑无需修改,直接调用即可正常执行:
List<EmployeeLocation> locations = Arrays.asList(new EmployeeLocation(), new EmployeeLocation()); Employee employee = new Employee(); employee.setEmployeeLocations(locations); employee.save();
方案2:一个员工仅对应一条地址
如果employee_location表和employee表是一对一关系,可使用@Embeddable实现,你之前报错是因为没有调整父类的关联注解:
1. 修改EmployeeLocation为嵌入类
// 去掉@Entity注解,改为@Embeddable @Embeddable class EmployeeLocation { // 不需要主键和关联Employee的注解 // 直接写地址相关字段即可 private String address; private String city; // ...其他字段 }
2. 修改Employee实体关联配置
@Entity(name = "employee") class Employee { @Id @Column(name = "id") @GeneratedValue private Long id; // 单条地址用@Embedded配置嵌入属性 @Embedded @AttributeOverrides({ @AttributeOverride(name = "address", column = @Column(name = "address")), @AttributeOverride(name = "city", column = @Column(name = "city")) }) private EmployeeLocation employeeLocation; // 若为多条地址用@ElementCollection配置 // @ElementCollection // @CollectionTable(name = "employee_location", joinColumns = @JoinColumn(name = "employee_id")) // private List<EmployeeLocation> employeeLocations; }
注意事项
- 不要在子实体的
@ManyToOne上配置CascadeType.ALL,否则删除子实体会级联删除关联的父员工数据,仅在父类的@OneToMany上配置级联即可。 - 双向关联必须手动维护子实体对父实体的引用,否则会出现外键为空的问题。
内容的提问来源于stack exchange,提问作者pickoneusername
相关产品推荐
相关产品推荐

