-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: lazy loading not working correctly
PostPosted: Tue Jan 03, 2006 12:59 pm 
Newbie

Joined: Fri Apr 22, 2005 3:17 am
Posts: 5
Hello everyone, i have a strange phenomenon regarding refreshing and updating lazy collections.

When running the testRefresh() method below everything is fine. But if you comment out the three code lines, the last line inside the try block will cause an NonUniqueObjectException. This is because the collection of Bs in A1 has been hydrated in line "Collection bs = a.getBs();". The root object A1 stays the same, also B1 stays the same, but the back reference in B (still inside the collection if the root object) to A1 changes.

When calling "s.refresh(a)" the back reference to A1 inside the B1 object does not longer point to the original A1 object. (In deed, they also are not equal in memory either.)

Is this a common behaviour in cases when using several sessions and detached, hierarchical objects?
Could you please confirm if it's a bug in the Hibernate implementation, or just the wrong usage of the session (thou i can't find where as this example is *really* simple). But if the use was wrong, please tell what to do to correct this.


Hibernate version: 3.1

Mapping documents:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
   "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

<hibernate-mapping package="hibernatedemo.models">

   <class name="A" table="A" select-before-update="true" lazy="false">
      <id name="id" type="long" unsaved-value="null">
         <column name="A_ID"/>
         <generator class="increment"/>
      </id>
      
      <property name="name" column="A_NAME"/>
      
      <set name="bs" lazy="true" inverse="true" cascade="all-delete-orphan">
         <key column="B_ID"/>
         <one-to-many class="B"/>
      </set>
   </class>
   
   <class name="B" table="B" select-before-update="true" lazy="false">
      <id name="id" type="long" unsaved-value="null">
         <column name="B_ID"/>
         <generator class="increment"/>
      </id>
      
      <property name="name" column="B_NAME"/>
      
      <many-to-one name="a" column="A_ID" class="A" cascade="none" lazy="false"/>
   </class>
   
</hibernate-mapping>



Structure Table A :
Code:
A_ID : int <pk>
A_NAME : VARCHAR2(50)


Table Data for A :
Code:
A_ID : 1
A_NAME : A1


Structure Table B:
Code:
B_ID : int <pk>
B_NAME : VARCHAR2(50)
A_ID : int <pk>


Table Data for B:
Code:
B_ID : 1
B_NAME : B1
A_ID : 1


Class A:
Code:
package hibernatedemo.models;

import java.util.*;

public class A {

   protected Long id;
   protected String name;
   protected Set<B> bs;

   public A() {
      this.bs = new HashSet<B>();
   }
   
   public Long getId() {
      return id;
   }

   public void setId( Long id ) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName( String name ) {
      this.name = name;
   }

   public Set<B> getBs() {
      return bs;
   }

   public void setBs( Set<B> bs ) {
      this.bs = bs;
   }

   public boolean equals( Object o ) {
      if ( !( o instanceof A ) ) {
         return false;
      }

      final A a = (A) o;

      if ( id != null ? !id.equals( a.id ) : a.id != null ) {
         return false;
      }
      if ( name != null ? !name.equals( a.name ) : a.name != null ) {
         return false;
      }

      return true;
   }

   public int hashCode() {
      int result;
      result = ( id != null ? id.hashCode() : 0 );
      result = 29 * result + ( name != null ? name.hashCode() : 0 );
      return result;
   }

}


Class B:
Code:
package hibernatedemo.models;

public class B {

   protected Long id;
   protected String name;
   protected A a;

   public B() {
   }

   public Long getId() {
      return id;
   }

   public void setId( Long id ) {
      this.id = id;
   }

   public String getName() {
      return name;
   }

   public void setName( String name ) {
      this.name = name;
   }

   public A getA() {
      return a;
   }

   public void setA( A a ) {
      this.a = a;
   }

   public boolean equals( Object o ) {
      if ( this == o ) {
         return true;
      }
      if ( !( o instanceof B ) ) {
         return false;
      }

      final B b = (B) o;

      if ( id != null ? !id.equals( b.id ) : b.id != null ) {
         return false;
      }
      if ( name != null ? !name.equals( b.name ) : b.name != null ) {
         return false;
      }

      return true;
   }

   public int hashCode() {
      int result;
      result = ( id != null ? id.hashCode() : 0 );
      result = 29 * result + ( name != null ? name.hashCode() : 0 );
      return result;
   }
}


Testcase that procuses an exception WHEN COMMENTS EXCLUDED:
Code:
package hibernatedemo;

import junit.framework.TestCase;
import hibernatedemo.models.*;
import org.hibernate.*;
import org.hibernate.cfg.Configuration;

import java.util.*;

public class RefreshTest
        extends TestCase {

   public void testRefresh() {
      try {
         SessionFactory sf = new Configuration().configure().buildSessionFactory();

         Session s = sf.openSession();
         assertFalse( s.isDirty() );
      
         //retrieve all As with name 'A1' (should be only 1)
         Collection col = s.createQuery( "from A a where a.name like 'A1'" ).list();
         assertNotNull( col );
         assertEquals( 1, col.size() );

         A a = (A) col.iterator().next();
         //hydrate lazy object
         assertEquals( "A1", a.getName() );
         
//         assertTrue( a.equals( a.getBs().iterator().next().getA() ) );
//         Collection bs = a.getBs();
         
      
         //close old session and reopen a new one
         s.close();
         s = null;
         assertNull( s );
         s = sf.openSession();
         assertNotNull( s );
         assertFalse( s.isDirty() );

         
//         assertTrue( a.equals( a.getBs().iterator().next().getA() ) );
         s.refresh( a );
         s.saveOrUpdate( a );

         
      } catch ( HibernateException he ) {
         he.printStackTrace();
         fail();
      } catch ( Exception e ) {
         e.printStackTrace();
         fail();
      }
   }

}


Full stack trace of any exception that occurs:
Code:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [hibernatedemo.models.A#1]
   at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.java:628)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.java:258)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.java:216)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:93)
   at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
   at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.java:520)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:513)
   at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.java:509)
   at hibernatedemo.RefreshTest.testRefresh(RefreshTest.java:219)


Name and version of the database you are using:
Oracle 8.1.7[quote][/quote]


Top
 Profile  
 
 Post subject: wrong SQL query created by Hibernate
PostPosted: Wed Jan 04, 2006 4:49 am 
Newbie

Joined: Fri Apr 22, 2005 3:17 am
Posts: 5
I recently noticed that the query for retrieving the collection of Bs is incorrect. It produces

Code:
select bs0_.B_ID as B1_2_, bs0_.B_ID as B1_1_1_, bs0_.B_NAME as B2_1_1_, bs0_.A_ID as A3_1_1_, a1_.A_ID as A1_0_0_, a1_.A_NAME as A2_0_0_ from TNT2.B bs0_, TNT2.A a1_ where bs0_.A_ID=a1_.A_ID(+) and bs0_.B_ID=1


but it should be:

Code:
select bs0_.B_ID as B1_2_, bs0_.B_ID as B1_1_1_, bs0_.B_NAME as B2_1_1_, bs0_.A_ID as A3_1_1_, a1_.A_ID as A1_0_0_, a1_.A_NAME as A2_0_0_ from TNT2.B bs0_, TNT2.A a1_ where bs0_.A_ID=a1_.A_ID(+) and a1_.A_ID=1


Top
 Profile  
 
 Post subject:
PostPosted: Wed Jan 04, 2006 5:31 am 
Newbie

Joined: Fri Apr 22, 2005 3:17 am
Posts: 5
ok, i got it, the mapping was wrong. It key column for the set of Bs in A must be A_ID, not B_ID.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.