I have en entity with a bidirectional hierarchical relationship :
public class Organization {
@ManyToOne(fetch = FetchType.LAZY)
public Organization getParent() {
return this.parent;
}
public void setParent(final Organization parent) {
if (parent == null || !parent.equals(this.getParent())) {
removeFromParent();
}
this.parent = parent;
}
@OneToMany(fetch = FetchType.LAZY, orphanRemoval = false)
@JoinColumn(name = "parent_id")
@OrderColumn(name = "parent_order")
public List<Organization> getOrganizations() {
return this.organizations;
}
public void setOrganizations(final List<Organization> organizations) {
organizations.stream().filter(org -> !this.equals(org.getParent())).forEach(org -> org.setParent(this));
this.organizations = organizations;
}
@PrePersist
void prePersist() {
addToParent();
}
@PreUpdate
void preUpdate() {
addToParent();
}
private void addToParent() {
if (parent != null && !parent.getOrganizations().contains(this)) {
parent.getOrganizations().add(this);
}
}
@PreRemove
void removeFromParent() {
if (parent != null) {
parent.getOrganizations().remove(this);
}
}
}
I need to be able to :
- set the parent from the child (which will be added at the end of the parent’s children list)
- add a child from the parent which will be inserted at any index of the children’s list
- move a child from a parent to another (or just removing the parent) without having a null element in my old parent’s children list afterward
But when creating an Organization and setting an existing Organization as its parent, the next call which loads the parent (read, update, delete) :
Organization otherParent = manager.read(otherParentId);
Organization someChild = newOrg("Some Child");
someChild.setParent(otherParent);
someChild = manager.create(someChild);
assertThat(otherParent.getOrganizations()).containsExactly(someChild);
manager.read(otherParentId); // throws HibernateException: null index column for collection: Organization.organizations
I’m probably doing something wrong but I don’t see what.
I have one hard contraint is that everything must be compliant with the java bean format.
I can have custom code inside the class, in the getters/setters and outside (annotations, …) but i can’t add methods like void addChild(Organization child)
because these methods will not be used by the controllers which are generated code and common to many entities.
I’ve also tried to manually manage the index with an @OrderBy and an Integer field to no avail.
I have pushed a full reproducer test case here (the test failing is creatingOtherChildrenWithParentOrg
) :