JPA Pitfalls (16): EntityManager.remove Does Not Remove Entity

This blog article is part of a “series of blog articles” about common pitfalls using JPA and ways to avoid them. In this article, we describe a problem with entites not beeing removed altough EntityManager.remove succeeds.

When calling EntityManager.remove on an entity referenced by a relationship, the EntityManager.remove call may succeed, but the related entity is not removed from the database. The following statement tries to remove the related insurance instance of an emplyoee entity:


Entity classes Emplyoee and Insurance have a bidirectional relationship annotated with cascade=PERSIST:
@OneToOne(mappedBy = "employee", 
          cascade = CascadeType.PERSIST)
private Insurance insurance;
@OneToOne(cascade = CascadeType.PERSIST)
private Employee employee;

At commit or flush all managed entities are synchronized to the database. This includes applying the persist operation to all relationships of the managed entities that are annotated with cascade=PERSIST. For the above case this means EM.persist is called for the removed Insurance entity. As a result the Insurace entity becomes managed again and is not removed from the database.

W/o the cascade=PERSIST annotation the persistent Employee entity would reference a non-persistent Insurance instance object at commit or flush. This results in an IllegalStateException and the transaction will fail on commit.

The correct code breaks the relationship by nullifying the insurance field in Employee entity and then remove the Insurance entity:

Insurance ins = emp.getInsurance();

You can find an example of this pitfall and its solution in the class RemoveExperiment in this project: