JPA同一实体双双向关联保存时报Column cannot be null如何解决
JPA级联保存步骤表与流转控制表非空约束报错问题
两个表分别是步骤表step、步骤流转控制表,后者用于记录当前步骤对应的下一个步骤。
步骤流转控制表查询语句:select * from cpo_workflow_step_control;
实体代码
Step实体代码
@Entity @Table(name = "cpo_workflow_step") public class CpoWorkflowStep implements java.io.Serializable { @Id @Column(name = "workflow_step_id") private String workflowStepId; // 省略workflow_id等其他基础字段 @OneToMany(fetch = FetchType.EAGER, mappedBy = "cpoWorkflowStepByWorkflowNextStepId", cascade = CascadeType.ALL, orphanRemoval = true) private Set<CpoWorkflowStepControl> cpoWorkflowStepControlsForWorkflowNextStepId = new HashSet<CpoWorkflowStepControl>(0); @OneToMany(fetch = FetchType.EAGER, mappedBy = "cpoWorkflowStepByWorkflowStepId", cascade = CascadeType.ALL, orphanRemoval = true) private Set<CpoWorkflowStepControl> cpoWorkflowStepControlsForWorkflowStepId = new HashSet<CpoWorkflowStepControl>(0); }
Step_Control实体代码
@Entity @Table(name = "cpo_workflow_step_control") public class CpoWorkflowStepControl implements java.io.Serializable { @Id @Column(name = "workflow_step_control_id") private String workflowStepControlId; @ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn(name = "workflow_next_step_id", nullable = false) private CpoWorkflowStep cpoWorkflowStepByWorkflowNextStepId; @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "workflow_step_id", nullable = false) private CpoWorkflowStep cpoWorkflowStepByWorkflowStepId; }
问题现象
通过JpaRepository的save方法保存包含所有Step及关联关系的Workflow对象,关联层级为1个Workflow对应多个Step,每个Step对应多个Step_Control。JPA在级联保存关联了Step_Control的Step时抛出报错,错误日志如下:
16:05:07.587 [http-nio-8004-exec-1] WARN o.h.e.jdbc.spi.SqlExceptionHelper - SQL Error: 1048, SQLState: 23000 16:05:07.587 [http-nio-8004-exec-1] ERROR o.h.e.jdbc.spi.SqlExceptionHelper - Column 'workflow_id' cannot be null
报错根因为cpoWorkflowStepControlsForWorkflowStepId属性关联的下游Step未完成持久化,导致关联字段为空。
解决方案
- 首先修正级联配置错误:删掉
CpoWorkflowStepControl实体中cpoWorkflowStepByWorkflowNextStepId字段上的CascadeType.ALL配置,该配置会触发JPA保存StepControl时自动级联保存关联的下一个Step,若这个Step还未绑定Workflow、也未提前持久化,就会直接触发workflow_id非空报错。 - 最稳妥的处理方式是拆分保存流程:先把所有关联Workflow的Step集合调用
saveAll批量持久化,确保所有Step的主键、关联的workflow_id都已写入数据库,再给每个Step设置对应的StepControl关联,同时维护好StepControl两端的Step引用,最后再保存Step集合或者直接保存StepControl集合即可,完全规避保存顺序问题。 - 若不想拆分保存逻辑,也可使用Hibernate专属的实体排序注解指定Step先于StepControl持久化,但该方式适配性差,后续关联逻辑调整很容易出问题,不推荐复杂关联场景使用。
- 额外注意:双向关联必须手动维护两端引用,给Step设置StepControl时,要同时给StepControl的
cpoWorkflowStepByWorkflowStepId和cpoWorkflowStepByWorkflowNextStepId赋值对应Step对象,避免级联时关联字段为空。
内容的提问来源于stack exchange,提问作者Aldo Inácio da Silva
相关产品推荐
相关产品推荐

