views:

5873

answers:

5

I have a situation in which I need to re-attach detached objects to a hibernate session, although an object of the same identity MAY already exist in the session, which will cause errors.

Right now, I can do one of two things.

1.) getHibernateTemplate().update( obj )
This works if and only if an object doesn't already exist in the hibernate session. Exceptions are thrown stating an object with the given identifier already exists in the session when I need it later.

2.) getHibernateTemplate().merge( obj ) This works if and only if an object exists in the hibernate session. Exceptions are thrown when I need the object to be in a session later if I use this.

Given these two scenarios, how can I generically attach sessions to objects? I don't want to use exceptions to control the flow of this problem's solution, as there must be a more elegant solution...

A: 

try getHibernateTemplate().saveOrUpdate()

Ben Hammond
saveOrUpdate will throw an exception just like update does.
Mark
+4  A: 

I think that merge is the proper way to reattach objects. The Hibernate API for Session.merge(obj) states the following

Copy the state of the given object onto the persistent object with the same identifier. If there is no persistent instance currently associated with the session, it will be loaded. Return the persistent instance. If the given instance is unsaved, save a copy of and return it as a newly persistent instance. The given instance does not become associated with the session. This operation cascades to associated instances if the association is mapped with cascade="merge".

This seems to contradict your claim that it works if and only if an object exists in the hibernate session. According to the Javadoc the instance will be loaded if it is not currently associated with the Session.

Mark
I had many problems preventing this from working. First of all, I needed to remember to udpate hibernate objects when they needed to be updated, and for the longest time I did not realize that session.merge RETURNED the new instance.
Stefan Kendall
For a good reference I would also recommend the Java Persistence with Hibernate book that cwash mentioned in his answer.
Mark
Yeah, the docs are good if you understand what Hibernate does and its intentions are already. If you do not, you either need to dive into the source... or look it up in JPwH. It's got a good index and will come to the rescue many times.
cwash
A: 

try getHibernateTemplate().replicate(entity,ReplicationMode.LATEST_VERSION)

Pavitar Singh
+1  A: 

Undiplomatic answer: You're probably looking for an extended persistence context. This is one of the main reasons behind the Seam Framework... If you're struggling to use Hibernate in Spring in particular, check out this piece of Seam's docs.

Diplomatic answer: This is described in the Hibernate docs. If you need more clarification, have a look at Section 9.3.2 of Java Persistence with Hibernate called "Working with Detached Objects." I'd strongly recommend you get this book if you're doing anything more than CRUD with Hibernate.

cwash
A: 

If you are sure that your entity has not been modified (or if you agree any modification will be lost), then you may reattach it to the session with lock.

session.lock(entity, LockMode.NONE);

It will lock nothing, but it will get the entity from the session cache or (if not found there) read it from the DB.

It's very useful to prevent LazyInitException when you are navigating relations from an "old" (from the HttpSession for example) entities. You first "re-attach" the entity.

Using get may also work, except when you get inheritance mapped (which will already throw an exception on the getId()).

entity = session.get(entity.getClass(), entity.getId());
John Rizzo
@John: I would like to re-associate an entity with session. Unfortunately, `Session.lock(entity, LockMode.NONE)` fails with exception saying: could not reassociate uninitialized transient collection. How can overcome this?
dma_k