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

JPA构建组织结构:首节点父节点为空触发PSQLException问题

Hey there, let's figure out why you're hitting that PSQLException when inserting the first node. I've gone through your code and spotted a few key issues that are causing this problem. Let's break them down one by one:

1. Bidirectional Association Mapping Conflict

Your @OneToMany and @ManyToOne annotations are both using @JoinColumn(name = "parent_id"), which creates a mapping conflict. In a bidirectional parent-child relationship, the @ManyToOne side is the owning side (it controls the foreign key), while the @OneToMany side should use mappedBy to reference the owning field instead of defining its own @JoinColumn.

Fix the Node entity mapping:

@Entity
@Table(name = "tree")
public class Node implements Serializable {
    @Id
    private int id;
    private String name;

    // Use mappedBy to point to the "parent" field in the child Node
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "parent", orphanRemoval = true)
    @OrderColumn
    @JsonManagedReference
    private Set<Node> children = new HashSet<>();

    @ManyToOne(fetch = FetchType.LAZY, optional = true)
    @JoinColumn(name = "parent_id", nullable = true)
    @JsonBackReference
    private Node parent;

    // Correct the addChild method logic
    public void addChild(Node child) {
        this.children.add(child);
        child.setParent(this);
    }

    // Getters and setters...
}

Note: I renamed the method to addChild for clarity, and added orphanRemoval = true to automatically remove child nodes if they're detached from the parent.

2. Broken Association Logic in addNode

Your original addNode method was trying to add the node to its own parent's children, which makes no sense for building a hierarchy. The correct logic is: when you add a child to a parent, you add the child to the parent's children set and set the child's parent reference to the parent itself.

3. Incorrect Controller Logic for Associating Nodes

Your current controller code calls node.addNode(node) on every node—this is essentially trying to add each node as a child of itself, which is totally wrong. Instead, you need to first save all nodes, then associate each child with its parent properly.

Updated Controller Code:

@RestController
@RequestMapping("/node")
public class NodeController {
    @Autowired
    private NodeRepository nodeRepository;

    @GetMapping
    public @ResponseBody Iterable<Node> index() {
        return nodeRepository.findByParentIsNull();
    }

    @PostMapping
    public String add(@RequestBody List<Node> nodes) {
        // First save all nodes to get them persisted in the database
        List<Node> savedNodes = nodeRepository.saveAll(nodes);
        
        // Now associate each child with its parent
        for (Node node : savedNodes) {
            if (node.getParent() != null && node.getParent().getId() != 0) {
                // Find the matching parent from the saved nodes list
                Node parent = savedNodes.stream()
                        .filter(n -> n.getId() == node.getParent().getId())
                        .findFirst()
                        .orElseThrow(() -> new RuntimeException("Parent node not found: " + node.getParent().getId()));
                parent.addChild(node);
            }
        }
        
        // Save the updated parent-child associations
        nodeRepository.saveAll(savedNodes);
        return "nice";
    }
}

4. Fix the Root Node's Parent in the Request Body

Your sample data sends parent:{} for the root node, which tells JPA to create an empty Node object instead of setting parent to null. Change the root node's parent field to null in your request:

[
    { "id":8, "name":"Top Parent", "parent":null },
    { "id":9, "name":"Node 1", "parent":{ "id":8 } },
    { "id":10, "name":"Node 2", "parent":{ "id":8 } },
    { "id":11, "name":"Node 3", "parent":{ "id":9 } }
]

Why This Works

  • The corrected mapping ensures JPA correctly handles the parent_id foreign key, allowing it to be null for root nodes.
  • The fixed addChild method properly establishes the parent-child relationship without circular references.
  • The controller now saves all nodes first, then links children to their parents—this avoids issues with unsaved parent entities that would cause database constraints to fail.
  • Sending parent:null instead of an empty object tells JPA explicitly that the root node has no parent, so it inserts null into the parent_id column as expected.

Give these changes a try—this should resolve the PSQLException and let you insert the entire hierarchy correctly in one go.

内容的提问来源于stack exchange,提问作者Febrinanda Endriz Pratama

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 06:24:56