JPA/Hibernate remove entity sometimes not working
I have the following code that usually works well:
public void delete(T object)
{
EntityManager em = getPersistence().createEntityManager();
EntityTransaction et = em.getTransaction();
try
{
et.begin();
object = em.find(object.getClass(), object.getId());
em.remove(object);
em.flush();
et.commit();
}
catch(Exception e)
{
error("Unable to delete " + object.toString() + ": there are references to it.");
}
finally
{
if (et.isActive()) et.rollback();
em.close();
}
}
For many of my entity classes this just works. However for two of them it does nothing, it does not throw any exceptions and it does not delete the object. The log from hibernate shows that hibernate executes a number of select queries but it doesn't even try to execute a delete.
I've already tried suggestions found in other similar questions here and here, but to no avail (well, the latter suggests @Transactional
which I can't use, but I just enclosed the statements between begin()
and commit()
instead).
I can't seem to find what those two classes have more (or less) than the others. They use @PrimaryKeyJoinColumn
just like almost all other entities I have, they have @OneToMany
and @ManyToOne
just like ohters. To be honest, they do have a @OneToOne(optional = false)
field that references another class and that other entities do not have, but I wouldn't go through the hassle of changing that (and consequently changing the database schema) unless you tell me there could be a reason for it.
Is @OneToOne
responsible? Or is my delete code bugged?
Do you have associations in this graph that cascade a persist back to the thing being deleted? If so, the JPA spec states clearly that the provider is to cancel the delete in such a case. If this is the case, Hibernate writes out a log statement saying "un-scheduling entity deletion [...]". You could see that by enabling trace logging on the org.hibernate.event.internal.DefaultPersistEventListener
logger.
If this is the situation, you'll need to clean up those associations as required by JPA specification.
Replacing the cascade = CascadeType.ALL
by orphanRemoval = true
in the @OneToMany
association gives the expected result: The child records are correctly removed without the need to delete the parent record.
Pity that error is not logged more clearly.
I got the same issue when following things gathered together.
- Hibernate 3.6.10.Final
- Parent entity with no reference to Child.
-
Some Child entity with reference to the Parent. It is legacy code.
class ChildEntity { @ManyToOne(cascade = CascadeType.ALL) private ParentEntity parent; }
Child entity is loaded into session context and then is removed from table without JPA notification within transaction (stored procedure, native sql)
Then parent can't be deleted. No deletion, no exception, just 'un-schedule deletion' message in TRACE log.
Solution: I removed cascade attribute. It was a little bit difficult for me to find which Child entity blocks Parent deletion. Also, I do not understand why Child cascade affects if I remove Parent entity.