Issue Details (XML | Word | Printable)

Key: HHH-511
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Minor Minor
Assignee: Steve Ebersole
Reporter: Gavin King
Votes: 84
Watchers: 64
Operations

If you were logged in you would be able to see more operations.
Hibernate Core

reattach object from same session

Created: 18/Feb/05 04:38 PM   Updated: 05/Nov/08 07:39 AM
Component/s: core
Affects Version/s: None
Fix Version/s: 3.2.4

Time Tracking:
Not Specified

File Attachments: 1. Text File reattach-same-session.patch (4 kB)
2. Text File reattach-same-session.patch (3 kB)

Issue Links:
Cause
 


 Description  « Hide
http://forum.hibernate.org/viewtopic.php?p=2231400#2231400

There is a problem when you reattach a collection to the same session that it was previously attached to, after calling clear(). Hibernate checks the collections session reference, at reattach and concludes it is already attached.

 All   Comments   Work Log   Change History   FishEye      Sort Order: Ascending order - Click to sort in descending order
Leonardo Quijano added a comment - 14/Sep/05 04:24 PM
A note on this: If you do an evict() on the collection's container object, then it works fine. Such as this:

      Load load = new Load();
      load.setStartTime(new Timestamp(System.currentTimeMillis()));
      load.setType("xxx");
      load.setStatus("xxx");
      load.addMessage("xxx");
      session.save(load);
      session.flush();
      session.evict(load);

      load.addMessage("yyy");
      session.update(load);
      session.flush();

koda added a comment - 03/Oct/05 11:42 PM
Here is another closely related issue:

    // Get a theme
    Theme theme = DefaultTheme.getRoot(session);
    
    // Get a child theme
    Theme childTheme = (Theme) theme.getChildren().iterator().next();
    
    // Evict it
    Serializable id = session.getIdentifier(childTheme);
    session.evict(childTheme);
    
    // Reload the child
    childTheme = (Theme) session.get(childTheme.getClass(), id);
    
    // This throws: org.hibernate.NonUniqueObjectException: a different object
    // with the same identifier value was already associated with the session
    // because the parent is still pointing to the old child. At flushing time,
    // it cascades saveOrUpdate() on the old child but the session already has
    // the new child (with the same id) associated with the session.
    session.flush();

Please consider increasing the priority of this issue as it makes it impossible to use long-term sessions for manipulating large objects. There doesn't seem to be a safe way to evict them from the session after they are used (to prevent OutOfMemoryError) and then reload them at a later time when they are referenced again.

Jose Peleteiro added a comment - 16/May/06 01:39 PM
+1
Please, consider this one.

Henrique Sousa added a comment - 14/Jun/06 02:35 PM
For EJB 3.0 this is failing due to a listener and and clear() is not called for the EntityManager. We must track changes to an entity, so in the pre-update callback we store a copy of the current entity and refresh it to get the old values. When I restore the updated state and let the flush() process continue this exception is raised. I cannot evict() the parent object because it still has to be saved and there is no such method in EntityManager.

Rodrigo S. de Castro added a comment - 08/Aug/06 03:00 PM
Patch against Hibernate 3.1.3

Apply it with: patch -p1 -i ./reattach-same-session.patch

I developed this patch to fix two problems I faced when reattaching objects to the session after clearing it:

- "reassociated object has dirty collection reference"
- "Found two representations of same collection: (collection type)"

This patch fixes this problem by allowing an object from a given session to be reattached. To do that, there are two minor changes in two classes:

- OnLockVisitor: in processCollection(), when a collection has been attached to the same session, we only throw an exception if the collection is dirty, otherwise we reattach this collection to the session and move on.

- Collections: in processReachableCollection() method, when a given collection is not found in the session persistence context, we check if it is a collection that has been previously attached to the session. If it is, we add this collection back to the persistence context. That fixes "Found two representations..." problem.

This code was tested and works just fine for me, fixing the problems I was facing. I hope this patch helps to solve the problems mentioned above.

PLEASE, check if this is the correct solution and review this code, in this case. I am not an expert in hibernate source code, so maybe there are other scenarios that reattaching objects is not allowed.

- Background

Some background of why I needed this problem fixed. Basically, I have a web application (spring mvc + hibernate) and wanted to develop JUnit tests for it. Using AbstractTransactionalSpringContextTests Spring class, each method is transactional, rolling back after its completion as a default behavior.

However, my goal was simulate several requests in a given method, ie, within a transaction (which happens to be per method). For that, everything would be perfect if I could clear hibernate session, in order to test the scenario where I have LazyInitializationException and similar problems:

public void testMethod1()
throws Exception {
// request1
request = new MockHttpServletRequest();
getCurrentSession().clear();
// .. request code ...

// request2
request = new MockHttpServletRequest();
getCurrentSession().clear();

// requestN
request = new MockHttpServletRequest();
getCurrentSession().clear();

}

But I had to implement thousands of workaround to avoid the problems mentioned above, what is impossible to maintain in the long run.

Danny Williams added a comment - 27/Sep/06 11:30 AM
Does any one know if this patch was made in the new version of hibernate? Thanks

Nándor Előd Fekete added a comment - 27/Sep/06 11:36 AM
Danny: if you'd like to have this patch included in your application, but you don't want to supply a patched recompiled version of hibernate, you could simply include those two patched files this patch affects in your classpath before the hibernate jar, ant the classloader will use the patched version of the classes. Later, when the bug gets fixed in a future release of hibernate you can simply remove the patched classes and switch to the new hibernate jar.

Rodrigo S. de Castro added a comment - 27/Sep/06 12:25 PM
Fixed some problems with previous patch. This version is on my production and development server.

HECTOR JUAREZ added a comment - 19/Mar/07 09:31 PM
Hibernate version: 3.1.3

Hi, I thinks this issue is related to another one:
When occurs an exception in a transactional method, the Hibernate session associated seems to be cleared, then when is executed another method with the same session and it tries to save an object that was in the session after the exception ocurrencie, the following exception is triggered: "org.springframework.orm.hibernate3.HibernateSystemException: Found two representations of same collection: org.appfuse.model.User.roles; nested exception is org.hibernate.HibernateException: Found two representations of same collection: <<collectionName>> "

For example:
BeanA
method {
User u = UserDao.getUser(1l);
 for (int i=0;i<=1;i++) {
    try {
         beanB.transactionalMethod(u);
    }catch (RuntimeException e) { System.err.println("RuntimeException ="+e);}
  }
}

BeanB
transactionalMethod(User u) {
   ...
   userDao.save(u);
}

Assuming that BeanA.method and BeanB.transactionalMethod are transactional and they are using the same Hibernate session, if an exception is triggered in the first call to transactionalMethod, then in the second call that method an exception will be triggered in userDao.save(u).
This exception is the commented above, and it happens because in the first method the hibernate session is cleared at the moment of the rollback, so it seems to have no entities and collections associated, but the exceptions is telling us another thing. This seems contradictory and it looks like Hibernate is not handling correctly this situation.
I was able to avoid this exeptions using session.refresh(u) before saving the user object, but I think that Hibernate should be handling this transparently.

Thanks.

Markus Bäurle added a comment - 22/Mar/07 02:48 PM
What is the current state of this bug?

I think the priority should be raised at least to major, because the needed workarounds are really ugly. What about the patch? Can it be applied into a new hibernate version?

I have the scenario above: The first transactional method throws an exception and the transaction is therefor rollbacked causing a clear() on the session. The following updates do not work anymore with the famous error message: Found two representations of same collection...

I use Spring with a HibernateInterceptor so I just cannot throw the session away and create a new one.

I solved the problem with a call to Session.merge() before update(), but this solution is ugly because merge() creates a new persistent instance, so I have to replace all references to the old detached instance with the new attached persistent instance. Unlike the scenario above I cannot use refresh() because it overwrites the current state with the state from the db discarding all changes.

Juozas Salna added a comment - 05/Apr/07 03:42 PM
as i understand patch is against hibernate 3.1
but we already work with 3.2

this is most voted bug in hibernate3
...

Steve Ebersole added a comment - 12/Apr/07 09:49 AM
Rodrigo, thanks for the patch. Initially I am inclined to think that the correct solution is to simply "unset" the session references for collections and proxies during clear (currently, they are simply removed from the session's persistence context, but their session reference is never cleared). Perhaps a better solution is to basically run evict() on all persistence context entries since evict does all of this work already.

Could you include test cases for all the scenarios you saw failing?

Steve Ebersole added a comment - 12/Apr/07 09:49 AM
Markus, regardless of what you want to do or dont want to do, throwing away the session is the only supported means for exception handling.

Steve Ebersole added a comment - 08/May/07 08:44 PM
Reported issue fixed on trunk / 3.2

Alex Pires de Camargo added a comment - 10/Oct/08 08:13 AM
This fix generated a problem on session.clear() performance, as posted on the forum:

http://forum.hibernate.org/viewtopic.php?t=990508

I've tested Rodrigo Castro patch with good results.





Alex Pires de Camargo added a comment - 05/Nov/08 07:05 AM
Patch for this fix probably generates HHH-3357