I'm working on a web application where I'm currently not able to persist certain entities because I get this exception:
"org.hibernate.PersistentObjectException: detached entity passed to persist: Entities.Person"
For a more complete understanding of the problem I will show you the most relevant code from my entities (They're related to each other in several steps so to see the connections I'm showing you 4 entities):
As you can see, the Cv entity is sort of the "base class" which all the other entities directly or indirectly are connected to.
In my application I let the user upload his or her cv in Word format. After that I let a session bean extract the names of skills which match a certain list from the cv. Then the found skills are shown to the user, who can edit or delete them and choose values for level and experience. The user can also create new skills.
Nothing is saved to the database until the user is completely satisfied and clicks "save". Then a servlet is called which reads all the needed information (which includes firstName, lastName and birthDate which the user has filled in, in the "upload cv page") from the current HttpSession object. After that the servlet creates a new Cv and tries to persist it. But when I try to do that I get the earlier mentioned exception:
"Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: Entities.Person"
That is.. I get that exception if the Person object already exists in the database and is retrieved to be connected to the newly created Cv entity. If I create a new Person everything works well and the new Cv is persisted. But I don't really understand Why it's working..
If the problem is that entities become detached as soon as they have been retrieved from the db and that causes problems when the detached entity is connected to a "new object" which should be persisted, then I think I should have problems in the "new Cv with a new Person" case as well.
I'll explain why I think so: For each Cv that is to be created I create or retrieve a Person object (as mentioned). But I also create a list of new Skillinstances, and as the code shows each Skillinstance has a connection to a Skill object - which in most cases already exists in the db and is just retrieved. The Skillcategories which the Skill objects are connected to are Always already in the db as well.
So I thought that there Would be a couple of detached Skill and Skillcategory entities, always, regardless of the state of the Person entity. Why doesn't this cause a problem but the Person entity does? And what should I do about it? Should I change the scope of the entity managers (for the moment they "live" inside entity facade session beans. One for each class) and in that case how?
I just want to know the best way to solve this, so if anyone has any good ideas I would be very grateful!
If you check the Hibnerate API, you'll see that a PersistentObjectException is thrown when the user passes a persistent instance to a Session method that expects a transient instance.
Since you didn't post your code for saving your object, I'll assume you're saving the CV with persist().
Because you've mapped the Person to be Cascade=ALL, it's trying to update the Person, which is a persistent instance (it's already been saved).
You may want to try using Session.merge() or Session.saveOrUpdate()
There will always be people who are ahead of the curve, and people who are behind the curve. But knowledge moves the curve. --Bill James
Joined: Feb 12, 2008
Thank you, for your reply, Stevi!
Yes, I did change the CascadeType for the person reference in the Cv entity to just MERGE, and I also removed a CascadeType.PERSIST from the ManyToOne relation skillId (in Skillinstance).
After that it worked to save a new cv though the person entity was "old".
I have another (related) problem though: If a new Cv is created for a certain person and that person has saved another Cv before, I want to remove that cv from the db. But when I try to do a remove operation (preceded by a merge in the bean method) I get this exception:
Before I try to remove it I collect the cv from the db using a JPQL query which finds a Cv entity (or actually a list of 2) by the person entity which is connected to it. (My servlet just calls the findByPerson method of the CvFacade session bean so the operation's done at a different "level", if that matters).
I thought that the persistence problem might somehow be caused by the cascade.DELETE operation on the Skillinstance list (thought I found it a bit unlikely).
A fact is that if you try to manually remove a cv by using only MySQL, it fails because my JoinTable(cv_skillinstance) + the cvRef field in the person table, refer to the specified cv (which means that some foreign key constraints fail).
So I decided to try to remove the involved entities in the same order as I do when I remove a cv manually (because that works).
Executing a native SQL query which removes the rows connected to the cv from my JoinTable works.
What doesn't work is getting the list of skillinstances from the "old" cv. Then I get this exception: "org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: Entities.Cv.skills, no session or session was closed"
At first I thought this happened because I'd already removed the connections in the JoinTable, so I moved the line where I access the list to before I remove the connections (to the skillinstances), but I still got the same exception.
Is this problem due to Hibernate being the persistence provider?
But can solving this problem help solving the problem of removing the cv entities themselves? - I actually think not since the exception I got said that the cv entity had become detached.. So now I'm back at my original question: Why does it become detached and what can I do about it? Should I start using explicit transactions or something?
I really want to get a deeper understanding of this, so I'd be Very grateful for some more help on this subject!