You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 05:05:45