We have an issue that sound like a bug in Hibernate dealing with orphanRemoval=true for a oneToMany List (with index).
Here is the simplified mapping :
public class ParentClass {
[...]
@OneToMany(cascade = ALL, mappedBy = "parent", orphanRemoval = true)
@OnDelete(action = OnDeleteAction.CASCADE)
@Fetch(FetchMode.JOIN)
@OrderColumn(name = "pos", nullable = false)
public List<ChildClass> getChildren() {
return children;
}
}
And the child class :
public class ChildClass {
[...]
@ManyToOne
@JoinColumn(nullable = false, name = "parent_id")
public ParentClass getParent() {
return parent;
}
}
Given this mapping, the following scenario is failing :
Here is the code
@Transactional
public void test() {
// 1)
ParentClass parent = entityManager.find(ParentClass.class, "some-id");
// 2)
ChildClass child = new ChildClass(parent);
parent.getChildren().add(child);
// 3)
entityManager.find(SomethingElse.class, "2");
// 4)
parent.getChildren().remove(child);
}
In that case, the child allocation is inserted into DB and not removed at te end of the transaction.
However, if we don't do step 3), the child allocation is correctly not persisted in DB
Is that a bug ? A wrong mapping ? Is there a workaround for it ?
Yes, that is a bug. I bet you don't use the last version of Hibernate (4.3.8), and that it is related (if not the same issue) to this issue: [HHH-9330] orphanRemoval=true does not work in bidirectional relationships (without cascading) Even if you use the last version, this bug could still exist. If so, please report it and then report the URL to the bug here somewhere. Workaround: try adding the child only when sure it must be persisted or also try setting to null the parent in the child:
child.setParent(null);
Also as another workaround you may try using Hibernate sessions, instead of EntityManager (as it is written in Hibernate's forum).
You need to set both sides of the association when removing a Child:
child.setParent(null);
parent.getChildren().remove(child);
The orphan-removal is not sufficient in your case. If the one-to-many side was a unidirectional association, then you could simply remove the Child from the List and the delete would propagate to the Child entity.
When you have a bi-directional association, you need to have both sides in sync. That's why you need to de-associate the Child from the Parent entity upon deletion.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With