Persisting a detached entity in JPA
In a JPA many to many relationship, if cascade type has been set at CascadeType.PERSIST (or CascadeType.ALL, which includes CascadeType.PERSIST), then while saving the parent and updating it with references of the child, it will try to save the child again.
@ManyToMany(cascade={CascadeType.PERSIST,CascadeType.MERGE,CascadeType.REFRESH},fetch = FetchType.EAGER) @JoinTable(name="QP_Q", joinColumns={@JoinColumn(name="questionpaperid")}, inverseJoinColumns=@JoinColumn(name="questionid"))
Following issues can appear
- Child is already in persistence store (A detached instance has been passed) -in this case it will throw an exception “org.hibernate.PersistentObjectException: detached entity passed to persist”
- Child is a new entry, then it will be added in its table and operation will complete successfully
Following are some solutions
- If requirement is that Parent should add a existing but detached child(creating an instance with same ID and passing on from the client) -it needs to be reattached to session first. Hmm -for this there is NO way in JPA -Nope, merge does not reattach and entity. If you are using hibernate, you are lucky, merge can do the trick
For JPA, best option would be to query for entity on server side before trying to save it. - If its sure that only new child will be added, and not an detached instance from DB, CascadeType.PERSIST will take care of
- On the other hand, if requirement is never to add a new child if its not alredy in DB then CascadeType.PERSIST should be removed and cascade={CascadeType.MERGE,CascadeType.REFRESH} should be used
@ManyToMany(cascade={CascadeType.MERGE,CascadeType.REFRESH},fetch = FetchType.EAGER) @JoinTable(name="QP_Q", joinColumns={@JoinColumn(name="questionpaperid")}, inverseJoinColumns=@JoinColumn(name="questionid"))
Posted on December 22, 2012, in Hibernate, Java and tagged detached entity, PersistentObjectException. Bookmark the permalink. 9 Comments.
Hi:
Excellent and to the point.
After hours lost, finally someone who gets to the point
Thanks, and excellent post
Thanks man. This post helped a lot.
Big thanks for this post. Solved a problem I have been struggling with for HOURS!
Very helpful, you saved me a lot of time. Thank you!
Thanks a lot its very use full. finally i got ans.
I was facing a similar issue, but I found a solution and the problem is not with JPA. Cascade.MERGE implies that a child will be merged when a parent is merged. In your case I am guessing that you are retrieving the existing parent from the db using entity manager and trying to update its fields and then do a jpa merge in the same transaction. During the updating of the entity you are setting a detached instance of a child to this entity in persistence context. when you do an em.merge, you are trying to merge an entity that is already in the persistence context. Thus em.merge will not merge the parent entity, thus none of your detached children are merged.
Solution:
You need to call ‘ em.detach(entity) ‘ before ’em.merge(entity)’,
This ensures that the parent is merged every time you call em.merge().
really helpful! i have finally resolved my issue with your post’s help 🙂
T H A N K S MAN!!!