在JPA中删除子项时保持实体关系同步

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在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;
    }
}

从父项中删除子项的代码如下(在此示例中,Parent可以在其列表中多次使用相同的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,然后将其从集合中删除。这使实体保持同步。我还可以做的是将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实体的列表,它们是否应设置为空?)该怎么办?

答案

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

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

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

如果Child与其他实体具有单向关系(即另一方没有保留Child实体列表,如果它们设置为null,该怎么办?)。

如果你不这样做,你会得到一个ConstraintViolationException,因为单向关联更像是多对多而不是一对多。有关更多详细信息,请查看我的JPA Relationships video course

以上是关于在JPA中删除子项时保持实体关系同步的主要内容,如果未能解决你的问题,请参考以下文章

JPA:在父子关系中->父未更新

在 Spring JPA 中删除实体

在 Spring Boot 中使用 JPA 从具有 OneToMany 关系的实体中删除对象

Hibernate - 删除子项时如何从父项中删除实体

如何在多对多关系上使用休眠和 JPA 删除孤立实体?

JPA / Hibernate - 删除子项删除父项(从同一个表)