首页 > 解决方案 > 在 JPA 中删除子项时保持实体关系同步

问题描述

我已经读到您需要使具有关系的实体保持同步,即当您从父级中删除子级时,您还应该在子实体中将保持父级的属性设置为 null。在我的示例中,我有以下父实体:

public class Parent {
    @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Child> children;
}

还有孩子:

public class Child {
    @ManyToOne(optional = false)
    private Parent parent;

    public void setParent(Parent parent) {
        this.parent = parent;
    }
}

从父级中删除子级的代码如下(在此示例中,aParent可以Child在其列表中多次包含相同的子级):

public void removeChild(Child child) {
    List<Child> childrenToRemove = this.children.stream()
        .filter(c -> c.equals(child))
        .collect(Collectors.toList());
    childrenToRemove.forEach(child -> child.setParent(null));
    this.children.removeAll(childrenToRemove);
}

我首先将Parent每个孩子的 NULL 设置为 NULL,然后将它们从集合中删除。这使实体保持同步。我还可以做的是将removeChild代码更改为以下内容:

public void removeChild(Child child) {
    this.children.removeIf(c -> c.equals(child));
}

当然,在这种情况下,实体不会保持同步,因为这些Child实体中的每一个仍然具有对Parent. 为了解决这个问题,我可以在Child实体中添加以下内容:

@PreRemove
public void preRemove() {
    this.parent = null;
}

我现在的问题是,如果Child实体也保存在不同父实体的列表中,例如AnotherParent也保存实体列表的Child实体,我是否也应该添加this.anotherParent = null@PreRemove上面定义的方法中?如果Child与其他实体有单向关系怎么办(即对方不保留Child实体列表,是否应该将它们设置为空?)。

标签: javahibernatejpaormentity-relationship

解决方案


您应该保持双向关联同步,以便实体状态转换可以传播并避免代码中难以跟踪的错误。

我现在的问题是,如果子实体也保存在不同父实体的列表中,例如也保存子实体列表的实体 AnotherParent,我是否应该也将 this.anotherParent = null 添加到定义的 @PreRemove 方法以上?

如果AnotherParent实体没有加载到当前运行的 Persistence cOntext 中,则不必这样做,因为内存中不存在父端集合。

如果 Child 与其他实体有单向关系怎么办(即对方没有保留 Child 实体的列表,是否应该将它们设置为 null?)。

如果你不这样做,你会得到一个ConstraintViolationException,因为单向关联更像是多对多而不是一对多。


推荐阅读