-->
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.  [ 5 posts ] 
Author Message
 Post subject: Update on a natural-id that references other entities fails
PostPosted: Thu Dec 27, 2007 4:26 am 
Newbie

Joined: Thu Nov 22, 2007 6:11 am
Posts: 6
Hello
I don't know if this is a bug but I created an entity referencing two other tables as a natural-id. When I execute the following code, it fails while replacing update with merge succeeds.
If this is not a bug please explain me why such an error occurs.

Thanks

Pascal

Hibernate version: 3.2.5.ga

Mapping documents:

A.hbm.xml
Code:
<hibernate-mapping>
<class name="test.A" table="A">
    <id name="id" type="long"  column="A_ID">
        <generator class="native"/>
    </id>
    <natural-id>
    <property name="name" type="string" column="NAME" />
    </natural-id>
    <property name="description" type="string" column="DESCRIPT" />
    </class>
</hibernate-mapping>


B.hbm.xml
Code:
<hibernate-mapping>
<class name="test.B" table="B">
    <id name="id" type="long"  column="B_ID">
        <generator class="native"/>
    </id>
    <natural-id>
    <property name="name" type="string" column="NAME" />
    </natural-id>
    <property name="description" type="string" column="DESCRIPT" />
    </class>
</hibernate-mapping>


AB.hbm.xml
Code:
<hibernate-mapping>
<class name="test.AB" table="A_B">
    <id name="id" type="long"  column="AB_ID">
        <generator class="native"/>
    </id>   

    <natural-id mutable="false">
      <many-to-one name="a" column="A_ID" class="test.A" />       
      <many-to-one name="b" column="B_ID" class="test.B" />       
    </natural-id>

    <property name="enabled" type="boolean" />     
    <property name="status" type="string" />
     
    </class>
</hibernate-mapping>


Code between sessionFactory.openSession() and session.close():

Code:
Session session = factory.getCurrentSession();
    session.getTransaction().begin();
   
    A a1 = new A();
    a1.setName("a1");
    a1.setDescription("a1 desc");
    session.save(a1);
   
    B b1 = new B();
    b1.setName("b1");
    b1.setDescription("b1 desc");
    session.save(b1);
   
    AB  ab = new AB();
    ab.setA(a1);
    ab.setB(b1);   
    ab.setEnabled(true);
    ab.setStatus("Original status");   
    session.save(ab);
   
    session.getTransaction().commit();
   
    ab.setEnabled(false);
   
    ab.setStatus("New Status");
   
    session = factory.getCurrentSession();
    session.getTransaction().begin();
   
    session.update(ab);
   
    session.getTransaction().commit();


Full stack trace of any exception that occurs:

Code:
Exception in thread "main" org.hibernate.HibernateException: immutable natural identifier of an instance of test.AB was altered
   at org.hibernate.event.def.DefaultFlushEntityEventListener.checkNaturalId(DefaultFlushEntityEventListener.java:87)
   at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:162)
   at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:113)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
   at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
   at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
   at test.TestMain2.main(TestMain2.java:87)


Name and version of the database you are using:Postgresql - 8.2.3

The generated SQL (show_sql=true):

Code:
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: select nextval ('hibernate_sequence')
Hibernate: insert into A (NAME, DESCRIPT, A_ID) values (?, ?, ?)
Hibernate: insert into B (NAME, DESCRIPT, B_ID) values (?, ?, ?)
Hibernate: insert into A_B (A_ID, B_ID, enabled, status, AB_ID) values (?, ?, ?, ?, ?)
Hibernate: select ab_.A_ID as A2_2_, ab_.B_ID as B3_2_ from A_B ab_ where ab_.AB_ID=?


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 27, 2007 7:08 pm 
Beginner
Beginner

Joined: Tue Oct 30, 2007 7:57 am
Posts: 47
I tried several things, but the only thing I can do is confirm the problem.

I just could see that update works if you make a session.refresh(ab) after opening the second transaction, but of course, you will lose any change made while object was detached. That seems to reatach the object to the session.

Code:
        session = factory.openSession();
        session.beginTransaction();
        session.refresh(ab);
        session.update(ab);
        session.getTransaction().commit();


Sorry not to be more useful


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 27, 2007 7:52 pm 
Beginner
Beginner

Joined: Tue Oct 30, 2007 7:57 am
Posts: 47
It seems a problem when comparing natural-id. I even tried mapping the natural-id as a component, but I get an error while commiting after the update. The ABNatural class, is Serializable, and implements equals and hashcode.

Code:
    <natural-id mutable="false">
        <component name="c" class="test.ABNatural" unique="true" >
            <many-to-one name="a" column="A_ID" class="test.A" />       
            <many-to-one name="b" column="B_ID" class="test.B" />       
        </component>
   </natural-id>


Exception in thread "main" org.hibernate.PropertyAccessException: IllegalArgumentException occurred calling getter of test.ABNatural.a
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:171)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValue(AbstractComponentTuplizer.java:64)
at org.hibernate.tuple.component.AbstractComponentTuplizer.getPropertyValues(AbstractComponentTuplizer.java:70)
at org.hibernate.tuple.component.PojoComponentTuplizer.getPropertyValues(PojoComponentTuplizer.java:86)
at org.hibernate.type.ComponentType.getPropertyValues(ComponentType.java:353)
at org.hibernate.type.ComponentType.isEqual(ComponentType.java:123)
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkNaturalId(DefaultFlushEntityEventListener.java:93)
at org.hibernate.event.def.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:169)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:120)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:196)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:76)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at test.TestManager.main(TestManager.java:51)
Caused by: java.lang.IllegalArgumentException: object is not an instance of declaring class
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.hibernate.property.BasicPropertyAccessor$BasicGetter.get(BasicPropertyAccessor.java:145)
... 15 more
Java Result: 1


Top
 Profile  
 
 Post subject:
PostPosted: Thu Dec 27, 2007 8:33 pm 
Beginner
Beginner

Joined: Tue Oct 30, 2007 7:57 am
Posts: 47
I made some more research, and definetively it seems a bug.

I overrided equals in classes A and B. If I return always true, it succesfully updates de AB object. The real problem, is that the equals method of A, does not receive an A object to compare, but a Long, which is the class of the id. Because of that, the method always returns false.

Hibernate should not call the A.equals method, but the Long.equals to compare the ids


Top
 Profile  
 
 Post subject:
PostPosted: Thu Jan 03, 2008 2:08 pm 
Newbie

Joined: Thu Nov 22, 2007 6:11 am
Posts: 6
Is there then something specific to do so that Hibernate team can confirm and in that case process that bug ?

Thanks anyway for your advice.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 5 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.