We have a tree of objects called Category where each category has zero or more child categories. Specifically:
@Entity
@Table(name = "category", schema = "customer")
public class Category extends AccountOwned implements OrdinalOwner {
@ManyToOne
@JoinColumn(name = "parent_category_id")
private Category parent;
@Column(name = "name")
private String name;
@Column(name = "ordinal")
private int ordinal;
@OneToMany(mappedBy = "parent", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
@OrderBy("ordinal")
private List<Category> children;
... getters/setters
}
We permit child categories to be moved around (their ordinal is changed) AND we permit them to move between parents.
I'm not using any explicit saves. The updates are wrapped in a Spring @Transactional.
If I have a tree like this:
Top Category
Item 1
Child 1a
Child 1b
Item 2
Child 2a
Item 3
Child 3a
Child 3b
Child 3c
I can move Item 3 under Item 1 as a child and it works. The tree is saved properly.
I can move Child 1b under Item 2 as a child and it also works. The tree is saved correctly.
However, if I move anything up the tree, the save doesn't work. For example, if move Child 1b under Top Category, Item 1-3 remain good, but Child 1b is gone forever.
As I move Child 1b to Top Category (by adding it to Top Category's children), I can see it getting removed from Item 1's children - which is good. I can see it correctly getting added to Top Category's children. And I can confirm that the parents of all categories are getting set correctly during the move.
It seems to me that JPA/Hibernate is detecting the removal of the child from one collection and performing a delete on the object, so when it reaches the add to the other list, the object is gone already.
This looks like a bug to me in Hibernate. Can anyone help. If it's a limitation of JPA/Hibernate, how can the logic be achieved?
EDIT: Hmmm, I can see several other people reporting this issue but not find any real solution. I'm using hibernate 5.1.1.