Hibernate @OneToMany关联抛出PSQLException:parent_id字段值为空
解决JPA保存父子实体时parent_id为空的异常
问题根源
你的双向关联配置中,ParentDto的@OneToMany使用了mappedBy = "parent",这指定了关联关系由Child端(拥有外键的一方)维护。当你直接保存Parent时,虽然配置了cascade = CascadeType.ALL,但请求映射后的ChildDto对象的parent属性为null,导致插入Child数据时parent_id字段为空,触发数据库非空约束异常。
修复步骤
1. 修正实体类错误
先修复实体类的两个问题:
ChildDto缺少@NoArgsConstructor,JPA要求实体必须有无参构造函数ParentDto的@OneToMany中targetEntity应为ChildDto.class,原代码写为Child.class是错误的
修改后的实体类代码:
@Entity @Table(name = "parent") @NoArgsConstructor @AllArgsConstructor @SequenceGenerator(name = "parentSequence", sequenceName = "parent_id_seq", allocationSize = 1) public class ParentDto implements Serializable { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "parentSequence") private Long id; private String name; @OneToMany(mappedBy = "parent", targetEntity = ChildDto.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER) private List<ChildDto> children; // 新增方法自动维护关联关系 public void addChild(ChildDto child) { if (children == null) { children = new ArrayList<>(); } child.setParent(this); children.add(child); } } @Entity @NoArgsConstructor @AllArgsConstructor @SequenceGenerator(name="childSequence", sequenceName = "child_id_seq", allocationSize=1) @Table(name = "child") public class ChildDto { @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "childSequence") private Long id; private String name; @ManyToOne @JoinColumn(name = "parent_id", nullable = false) private ParentDto parent; // 添加Setter方法(若未生成) public void setParent(ParentDto parent) { this.parent = parent; } }
2. 保存前手动维护关联
调用parentDao.save()之前,确保每个ChildDto都关联到对应的ParentDto,可以用上面新增的addChild方法处理:
// 假设request解析后得到ParentDto对象 ParentDto parent = request.getParent(); if (parent.getChildren() != null && !parent.getChildren().isEmpty()) { List<ChildDto> processedChildren = new ArrayList<>(); for (ChildDto child : parent.getChildren()) { parent.addChild(child); processedChildren.add(child); } parent.setChildren(processedChildren); } parentDao.save(parent);
3. 可选:简化关联维护
可以在ParentDto的setChildren方法中自动处理关联,省去手动遍历的步骤:
public void setChildren(List<ChildDto> children) { if (children == null) { this.children = null; return; } this.children = children; children.forEach(child -> child.setParent(this)); }
后续只要给Parent设置children集合,就会自动给每个Child绑定Parent关联。
核心原理
JPA双向关联中,只有维护端(拥有外键的ChildDto)的关联属性会被持久化到数据库。即便配置了级联保存,若维护端的关联属性为null,JPA不会自动填充外键,必须手动建立关联关系。
内容的提问来源于stack exchange,提问作者annswerg
相关产品推荐
相关产品推荐

