- Wildfly 21
- Hibernate 5.3.18.Final (JPA provider)
I stumbled in a very strange and nonintuitive behaviour in Hibernate.
PhoneId
@Embeddable
public class PhoneId
{
@Column(name = "PERSON_ID")
private int personId;
@Column(name = "PHONE_ID")
private int phoneId;
// Getters, setters...
}
Phone
@Entity
public class Phone
{
@EmbeddedId
private PhoneId id;
private String number;
@ManyToOne
@JoinColumn(name = "person_id")
private Person person;
// Getters, setters...
}
Person
@Entity
public class Person
{
@Id
private int id;
@OneToMany(mappedBy = "person", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Phone> phones = new ArrayList<>();
// Getters, setters...
}
Now, suppose that I have these phones in the database associated with person with id 1:
- PERSON_ID=1, PHONE_ID=1, NUMBER=phone1
- PERSON_ID=1, PHONE_ID=2, NUMBER=phone2
The I get a person:
Person person = em.find(Person.class, 1);
person.getPhones().size() // 2
and, working with it in detached mode, I change the two phone ids to 3 and 4, respectively. I also add a third phone with id 5 to this person. After that, I want to update the database with these changes with:
person.getPhones().size() // 3
Person newPerson = em.merge(person);
So, the problem is this:
After that, I would expect to see in the phones table in the database these records:
- PERSON_ID=1, PHONE_ID=3, NUMBER=phone1
- PERSON_ID=1, PHONE_ID=4, NUMBER=phone2
- PERSON_ID=1, PHONE_ID=5, NUMBER=phone3
But do you know what I see? I actually see this:
- PERSON_ID=1, PHONE_ID=1, NUMBER=phone1
- PERSON_ID=1, PHONE_ID=2, NUMBER=phone2
- PERSON_ID=1, PHONE_ID=3, NUMBER=phone1
- PERSON_ID=1, PHONE_ID=4, NUMBER=phone2
- PERSON_ID=1, PHONE_ID=5, NUMBER=phone3
So, when I saved the changes to the database I had only 3 phones in the collection and Hibernate didn’t delete the phones that were in the database (their ids were no longer in the phone collection) and added to them in the database the phones with the new ids. What’s happening here? What’s the use of the orphanRemoval
attribute if it doesn’t remove the childs with ids that were no longer in the phones collection?
If I have only 3 phones in a collection I want to have only 3 phones in the database as well. Very fair. Why is Hibernate ignoring the phones that are already in the database and not deleting them? After all, the phones in the database have different ids than those in the collection.
This is completely nonintuitive and wrong in my opinion, but if I’m missing something or doing something wrong, I would like very much to know.