I have had a problem since Hibernate 4.1.8 resulting in the following exception:
org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [test.hibernate.TestPrepravkaOsobaSAdresou$Uvazek#2]
I have a simple OneToMany association between two entities:
@Entity(name = "Ppv")
@Table(name = "PPV")
public static class Ppv {
@Id
Long ppvId;
@OneToMany(fetch = FetchType.EAGER, mappedBy = "ppv")
Set<Uvazek> uvazeks = new HashSet<Uvazek>(0);
}
@Entity(name = "Uvazek")
@Table(name = "UVAZEK")
public static class Uvazek {
@Id
Long uvazekId;
@ManyToOne
@JoinColumn(name = "PPV_FXID")
Ppv ppv;
}
and a test case where I have one Ppv and two Uvazek. When I load and detach a Ppv, delete one Uvazek associated with loaded Ppv and merge Ppv I get an exception.
jdbcTemplate.execute("insert into PPV values(1)");
jdbcTemplate.execute("insert into UVAZEK values(2, 1)");
jdbcTemplate.execute("insert into UVAZEK values(3, 1)");
Ppv ppv = (Ppv) getSession().get(Ppv.class, 1l);
getSession().clear();
getSession().delete(getSession().get(Uvazek.class, 2l));
getSession().flush();
getSession().merge(ppv);
getSession().flush(); //Causes the exception
During the Ppv merge, Hibernate tries to load the deleted Uvazek. Even though Uvazek is deleted, Hibernate still has information about it in
org.hibernate.collection.internal.AbstractPersistentCollection.storedSnapshot
on uvazek's set on the detached Ppv. In a previous version (<4.1.8) this works. In this simple example I can repair it by adding orphanRemoval=true
on uvazeks set on Ppv and instead of deleting uvazek remove it from uvazeks set on Ppv.
So my question is: Is this a Hibernate bug or my bad practice?
The problem is that the Uvazek with id = 2 is attempted to be merged. Hibernate sees that it has a key, but it does not know if the object is dirty, so it's not clear if an SQL update should be made.
But because the key is 2, Hibernate knows that the object has to exist on the database, so it tries to load the object in order to compare it to the version it just received in memory, to see if the object has some pending modifications to be synchronized to the database.
But the select returns no results, so Hibernate has contradictory information: on one hand the database says the object does not exist. On the other hand, the object in memory says the object must exist with key 2. There is no way to decide which is correct, so the ObjectNotFoundException
is thrown.
What happened is that before this version the code was accidentally basing itself on a bug that meanwhile got fixed, so this no longer works.
The best practice is to avoid clear and use it only if needed as a memory optimization, by clearing only objects that you know won't be modified or needed in the same session anymore, have a look at Is Session clear() considered harmful.
You also need to remove the reference to Uvazek from Ppv. Otherwise Hibernate tries to restore the relation when you merge it back and fails, because you deleted the referenced Uvazek.
This is also why adding orphan removal works for you.
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