JPA Detached Object Gotchas

Java Persistence API detached object gotchas

One of the issues to get your head around in both Hibernate and JPA is how to handle detached entities. In Hibernate one has to deal with the session object and in JPA it is called the persistence context.

The most common solution is to re-attach your entities to a new persistence context when they need to be flushed to the database again. In JPA one uses the merge function to attached a detached object to the current persistence context. Lets say we have a person object and a company object, with a person belonging to a company. To reattached the detached person object one has to do: (em is a valid EntityManager object)

em.merge(person);

The mistake people often make, is that the merge function returns an new, ie separatet, attached object of the same type as the detached object and updated for the changes in the detached object. This object is not the same object as the detached instance you sent into the method. So the following will not work:

em.merge(person)
company.setPerson(person)
em.persist(company)

Instead you need to go:

person = em.merge(person)
company.setPerson(person)
em.persist(company)

or

company.setPerson(merge(person))
em.persist(company)

The same applies for updating or merging an object with foreign entities. This approach is mandated by the JPA specification, although I am sure they had their reasons it is a cause of many lost hours in debugging when you first start trying out JPA.

Comments

I have been banging my head against the wall because of this issue. I applied your clear solution and my code is finally working!

This also works for me and I was so glad when I did it with no help and it is so nice the fact that before reading this I didn't know how to do. Now I'm specialized. :D

Bit catchy but absorb CAN be fabricated to behave absolutely like saveOrUpdate application the id generated key. For my article I acclimated the acreage “id” as generated key. If this is id aught or not already in database, the article administrator absorb alarm will actualize a new almanac (persist article in JPA lingo). However, if that id is non-zero that already exists in database, absorb will amend the object.

we are having a problem with JPA merge.. we have a customer table and address table with onetomany relationship. so we created a intermediate table ‘customeraddress’. when we go for the customer update test case, we have the customerid and addressid, but the id for customeraddress object is not available.. so its inserting a new row for customeraddress, there by duplicating the customeraddress row. we try to use the merge on the customer object with cascadetype ‘ALL’. how to sovle this problem?