Hibernate单向一对一映射插入时EMPLOYEE_ID非空约束错误如何解决?
问题1:Hibernate尝试先保存子实体再保存父实体的原因
- 关联注解配置完全搞反了外键持有关系:你把
@JoinColumn注解加在Employee类的empDetail字段上,且指定的name="EMPLOYEE_ID"是Employee表的主键字段。这个配置的语义是Employee表的EMPLOYEE_ID字段作为外键关联到EmployeeDetail表的主键,相当于父表要依赖子表的主键值才能完成插入,因此Hibernate会优先保存子实体,再保存父实体,和你预期的执行顺序完全相反。 EmployeeDetail实体没有建立正确的关联映射:你仅在类中定义了普通的employeeId字段,没有声明它和Employee实体的关联关系,Hibernate无法感知这个字段和父实体主键的绑定逻辑,自然不会自动填充父实体生成的主键值,导致插入子表时EMPLOYEE_ID为NULL触发非空约束报错。
问题2:正确的实体映射配置
你的场景属于外键存放在子表的一对一关联,子表有独立主键、仅通过employee_id关联父表且有唯一约束,按以下步骤调整即可:
第一步:修改Employee实体的关联配置
移除错误的@JoinColumn,添加mappedBy属性指定关联的持有方为子实体的employee字段:
@Entity @Table(name = "EMPLOYEE") public class Employee implements Serializable { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "empgen") @SequenceGenerator(name = "empgen", sequenceName = "SEQ_EMP", allocationSize = 1) @Column(name = "EMPLOYEE_ID") private Long id; @Column(name = "SALARY") private Long salary; // 新增mappedBy声明关联由子实体维护 @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "employee") private EmployeeDetail empDetail; // 省略getter、setter }
第二步:修改EmployeeDetail实体的关联配置
删除单独的employeeId字段,新增和Employee的关联映射,把@JoinColumn加在子实体的关联字段上,匹配数据库的外键和唯一约束:
@Entity @Table(name = "EMPLOYEE_DETAIL") public class EmployeeDetail implements Serializable { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "empdetgen") @SequenceGenerator(name = "empdetgen", sequenceName = "SEQ_EMP_DET", allocationSize = 1) @Column(name = "EMPLOYEE_DETAILS_ID") private Long id; // 新增关联映射,匹配数据库外键约束 @OneToOne @JoinColumn(name = "EMPLOYEE_ID", nullable = false, unique = true) private Employee employee; @Column(name = "ADDRESS") private String address; @Column(name = "GENDER") private String gender; // 省略getter、setter }
第三步:持久化前补全双向关联
调用保存接口前,手动给子实体设置父实体实例,级联保存时Hibernate会自动填充外键值:
// employee为JSON反序列化得到的实例 employee.getEmpDetail().setEmployee(employee); employeeRepository.save(employee);
额外注意
你提交的JSON参数里address字段拼写错误为adress,会导致反序列化时地址字段为空,需要修正拼写。
内容的提问来源于stack exchange,提问作者Mike Wallace
相关产品推荐
相关产品推荐

