In my application, there is a Person entity that has numerous roles of type PersonRole.
@Entity
public class Person {
@OneToMany(mappedBy = "person",
cascade=CascadeType.ALL,
orphanRemoval=true,
fetch=FetchType.LAZY)
protected Set<PersonRole> roles;
...
}
@Entity
public abstract class PersonRole {
@ManyToOne
protected Person person;
...
}
Occassionally there are duplicate persons in the database and I'm trying to implement a function to merge those two persons into one. Since the PersonRole also has some Permissions attached to it, I don't want to delete and recreate it, I want to move it from the dieing Person to the surviving Person:
for (PersonRole role : dieing.getRoles()) {
role.mergeInto(surviving);
}
dieing.getRoles().clear();
the Method in PersonRole looks like this:
public void mergeInto(Person surviving ) {
this.person = surviving;
surviving.getRoles().add(this);
}
Unfortunately it doesn't work. When I run it, the PersonRoles are deleted and not added to the surviving person.
What do I need to change, so they are added and persisted through the surviving.roles relationship?
I found the solution:
dieing.getRoles().clear();
was wrong. I removed that line and now it works.
While this is a solution, I'm not happy with the way JPA / Hibernate work here. The surviving Person is "stealing" the entities from the "dieing" Person without the "dieing" Person first releasing them. So if I don't em.update(dieing) after a flush, I have a contradictory model.