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 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:
Insurance have a bidirectional relationship annotated with
Emplyoee.java: @OneToOne(mappedBy = "employee", cascade = CascadeType.PERSIST) private Insurance insurance; Insurance.java: @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.
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 ins = emp.getInsurance(); emp.setInsurance(null); em.remove(ins);
You can find an example of this pitfall and its solution in the class RemoveExperiment in this project: https://github.com/akquinet/jpapitfalls.git.