Issue
I've read that you need to keep entities that have a relationship in sync, i.e. when you remove a child from a parent you should also set the attribute that holds the parent to null in the child entity. In my example I have the following parent entity:
public class Parent {
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Child> children;
}
And the child:
public class Child {
@ManyToOne(optional = false)
private Parent parent;
public void setParent(Parent parent) {
this.parent = parent;
}
}
The code for removing a child from the parent is as follows (in this example a Parent
can have the same Child
in its list multiple times):
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);
}
I first set the Parent
to NULL on each of the children and then remove them from the collection. This keeps the entities in sync. What I could also do is change the removeChild
code to the following:
public void removeChild(Child child) {
this.children.removeIf(c -> c.equals(child));
}
Of course in this case the entities are not kept in sync because each of those Child
entities still has a reference to the Parent
. To remedy that I could add the following to the Child
entity:
@PreRemove
public void preRemove() {
this.parent = null;
}
My question now is, what if Child
entity is also kept in a list of a different parent entity, e.g. the entity AnotherParent
which also keeps a list of Child
entities, should I then also add this.anotherParent = null
to the @PreRemove
method defined above? What if Child
has unidirectional relationship with other entities (i.e. the other side doesn't keep a list of the Child
entities, should they be set to null?).
Solution
You should keep the bidirectional associations in sync so that the entity state transitions can propagate and to avoid hard-to-track bugs in your code.
My question now is, what if Child entity is also kept in a list of a different parent entity, e.g. the entity AnotherParent which also keeps a list of Child entities, should I then also add this.anotherParent = null to the @PreRemove method defined above?
If the AnotherParent
entity is not loaded in the currently running Persistence cOntext, you don't have to do that because the parent-side collection does not exist in memory.
What if Child has unidirectional relationship with other entities (i.e. the other side doesn't keep a list of the Child entities, should they be set to null?).
If you don't do that, you'll get a ConstraintViolationException
because unidirectional associations are more like many-to-many than one-to-many.
Answered By - Vlad Mihalcea