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

时间:2018-08-08 09:37:14

标签: java hibernate jpa orm entity-relationship

我了解到,您需要保持具有关联关系的实体同步,即,当您从父级中删除子级时,还应该将在子实体中将父级保留为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实体的列表,应该将它们设置为null怎么办?)。

1 个答案:

答案 0 :(得分:1)

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

  

我现在的问题是,如果子实体也保留在   不同的上级实体,例如实体AnotherParent   保留子实体的列表,然后我还应该添加   上面定义的@PreRemove方法的this.anotherParent = null吗?

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

  

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

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