-->
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.  [ 6 posts ] 
Author Message
 Post subject: identifier altered using composite-id, EntityMode=Map
PostPosted: Tue Mar 08, 2005 6:47 am 
Newbie

Joined: Thu Jan 08, 2004 11:54 am
Posts: 10
Keep getting this -
Code:
org.hibernate.HibernateException: identifier of an instance of TestEntity altered from {key1=1, key2=1} to {key1=1, prop1=test, type=TestEntity, key2=1}


...when I haven't touched the Map.

Looks like it's confusing the whole Map with the subset of the Map used for the identifier.

Suggestions / workarounds?

Many thanks
Jeremy.


Using "dynamic-class"

Hibernate version: 3.0rc1

Mapping documents:

Code:
<hibernate-mapping>
  <class entity-name="TestEntity" table="HIBTEST" schema="MARS">
    <composite-id>
      <key-property name="key1" type="java.lang.Long"/>
      <key-property name="key2" type="java.lang.Long"/>
    </composite-id>
    <property name="prop1" type="java.lang.String">
      <column name="col1" sql-type="VARCHAR2"/>
    </property>
  </class>
</hibernate-mapping>

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

Code:
   Configuration cfg = new Configuration();
    cfg.setProperty(Environment.DEFAULT_ENTITY_MODE, EntityMode.MAP.toString());
    cfg.addFile("classes/test/test.hbm.xml");
   
    cfg.configure();
    SessionFactory factory = cfg.buildSessionFactory();
       
   
    Session s = factory.openSession();
    Transaction tx = null;
    try
    {
      // s.setFlushMode(FlushMode.NEVER); //entirely optional!!
      tx = s.beginTransaction();
 
      log("Getting a test entity");
      Map si = (Map) s.createQuery(
          "from TestEntity te where te.key1='1' and te.key2='1' "
          ).uniqueResult();
 
      /*
      for (Iterator attrs = si.keySet().iterator(); attrs.hasNext(); )
      {
        String attrName = (String) attrs.next();
        log(attrName+ " = "+ si.get(attrName));
      }
      */
     
      tx.commit();
    }
    catch (Exception e)
    {
      if (tx != null) tx.rollback();
      throw e;
    }
    finally
    {
      s.close();
    }
   
  }
 


Full stack trace of any exception that occurs:
Code:
Getting a test entity
Hibernate: select testentity0_.key1 as key1_, testentity0_.key2 as key2_, testentity0_.col1 as col3_0_ from MARS.HIBTEST testentity0_ where (testentity0_.key1='1' and testentity0_.key2='1')
org.hibernate.HibernateException: identifier of an instance of TestEntity altered from {key1=1, key2=1} to {key1=1, prop1=test, type=TestEntity, key2=1}
   at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:51)
   at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:82)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:190)
   at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:70)
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:669)
   at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:293)
   at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
   at test.HibTestCase.main(HibTestCase.java:54)
Exception in thread "main"

Name and version of the database you are using:
Oracle 9.2.0.4


The generated SQL (show_sql=true):
Code:
Hibernate: select testentity0_.key1 as key1_, testentity0_.key2 as key2_, testentity0_.col1 as col3_0_ from MARS.HIBTEST testentity0_ where (testentity0_.key1='1' and testentity0_.key2='1')


Debug level Hibernate log excerpt:
10:18:20,767 DEBUG QueryTranslatorImpl:177 - HQL: from TestEntity te where te.key1='1' and te.key2='1'
10:18:20,767 DEBUG QueryTranslatorImpl:178 - SQL: select testentity0_.key1 as key1_, testentity0_.key2 as key2_, testentity0_.col1 as col3_0_ from MARS.HIBTEST testentity0_ where (testentity0_.key1='1' and testentity0_.key2='1')
10:18:20,767 DEBUG AbstractBatcher:258 - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
10:18:20,767 DEBUG SQL:292 - select testentity0_.key1 as key1_, testentity0_.key2 as key2_, testentity0_.col1 as col3_0_ from MARS.HIBTEST testentity0_ where (testentity0_.key1='1' and testentity0_.key2='1')
Hibernate: select testentity0_.key1 as key1_, testentity0_.key2 as key2_, testentity0_.col1 as col3_0_ from MARS.HIBTEST testentity0_ where (testentity0_.key1='1' and testentity0_.key2='1')
10:18:20,767 DEBUG AbstractBatcher:343 - preparing statement
10:18:20,798 DEBUG AbstractBatcher:274 - about to open ResultSet (open ResultSets: 0, globally: 0)
10:18:20,798 DEBUG Loader:377 - processing result set
10:18:20,798 DEBUG Loader:382 - result set row: 0
10:18:20,830 DEBUG LongType:86 - returning '1' as column: key1_
10:18:20,830 DEBUG LongType:86 - returning '1' as column: key2_
10:18:20,830 DEBUG Loader:719 - result row: EntityKey[TestEntity#{key1=1, key2=1}]
10:18:20,830 DEBUG Loader:864 - Initializing object from ResultSet: [TestEntity#{key1=1, key2=1}]
10:18:20,830 DEBUG BasicEntityPersister:1625 - Hydrating entity: [TestEntity#{key1=1, key2=1}]
10:18:20,830 DEBUG StringType:86 - returning 'test' as column: col3_0_
10:18:20,845 DEBUG Loader:399 - done processing result set (1 rows)
10:18:20,845 DEBUG AbstractBatcher:281 - about to close ResultSet (open ResultSets: 1, globally: 1)
10:18:20,845 DEBUG AbstractBatcher:266 - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
10:18:20,845 DEBUG AbstractBatcher:363 - closing statement
10:18:20,845 DEBUG Loader:450 - total objects hydrated: 1
10:18:20,845 DEBUG TwoPhaseLoad:96 - resolving associations for [TestEntity#{key1=1, key2=1}]
10:18:20,845 DEBUG TwoPhaseLoad:167 - done materializing entity [TestEntity#{key1=1, key2=1}]
10:18:20,845 DEBUG PersistenceContext:738 - initializing non-lazy collections
10:18:20,845 DEBUG JDBCTransaction:83 - commit
10:18:20,845 DEBUG SessionImpl:292 - automatically flushing session
10:18:20,845 DEBUG AbstractFlushingEventListener:52 - flushing session
10:18:20,845 DEBUG AbstractFlushingEventListener:102 - processing flush-time cascades
10:18:20,845 DEBUG AbstractFlushingEventListener:150 - dirty checking collections
10:18:20,845 DEBUG AbstractFlushingEventListener:167 - Flushing entities and processing referenced collections
10:18:20,861 DEBUG JDBCTransaction:124 - rollback
10:18:20,861 DEBUG JDBCContext:208 - before transaction completion
10:18:20,861 DEBUG SessionImpl:337 - before transaction completion
10:18:20,861 DEBUG JDBCTransaction:135 - rolled back JDBC Connection
10:18:20,861 DEBUG JDBCContext:213 - after transaction completion
10:18:20,861 DEBUG SessionImpl:353 - after transaction completion
10:18:20,861 DEBUG SessionImpl:246 - closing session
10:18:20,861 DEBUG AbstractBatcher:394 - closing JDBC connection (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)
10:18:20,861 DEBUG DriverManagerConnectionProvider:129 - returning connection to pool, pool size: 1
10:18:20,861 DEBUG JDBCContext:213 - after transaction completion
10:18:20,861 DEBUG SessionImpl:353 - after transaction completion
org.hibernate.HibernateException: identifier of an instance of TestEntity altered from {key1=1, key2=1} to {key1=1, prop1=test, type=TestEntity, key2=1}
at org.hibernate.event.def.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:51)
at org.hibernate.event.def.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:82)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:190)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:70)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:26)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:669)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:293)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at test.HibTestCase.main(HibTestCase.java:54)
Exception in thread "main"


Top
 Profile  
 
 Post subject: still happens when I use session.load instead of query
PostPosted: Tue Mar 08, 2005 9:14 am 
Newbie

Joined: Thu Jan 08, 2004 11:54 am
Posts: 10
I get the same exception with this code too:
Code:
HashMap si = new HashMap();
      si.put("key1", new Long(1));
      si.put("key2", new Long(1));
     
      log("Getting a test entity");

      /* not sure if doco implies I shouldn't use this:
      Map si = (Map) s.createQuery(
          "from TestEntity te where te.key1='1' and te.key2='1' "
          ).uniqueResult();
      */
     
      Map s2 = (Map) s.load("TestEntity", si);

It finds and loads the Map OK, but when I commit the session it always barfs. The docs do say -
Quote:
Unfortunately, this approach to composite identifiers means that a persistent object is its own identifier.

But I don't see how to get round this when using a dynamic Map for my Java entity (ie eneity-mode=Map) - I am in a situation where I can't (really) define a concrete class for the composite id.
Something in the hibernate session-flush code has the same problem; I can see it trying to compare two Maps, one with just the key fields, and one which is the whole entity. But I haven't been able to localise the source of the problem.


Top
 Profile  
 
 Post subject:
PostPosted: Tue Mar 08, 2005 12:14 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
(1) I fixed the problem in CVS
(2) you can workround by not using an embedded composite identitifier - supply a named attribute which holds the composite id


Top
 Profile  
 
 Post subject: am I getting the latest CVS?
PostPosted: Thu Mar 10, 2005 6:13 am 
Newbie

Joined: Thu Jan 08, 2004 11:54 am
Posts: 10
Many thanks to Gavin for the fix & workaround.

I am currently managing with this workaround, which I think matches Gavin's suggestion:

Code:
  <composite-id name="id" class="test.CompositeKey" >
      <key-property name="key1" column="akey1" />
      <key-property name="key2" column="akey2" />
   </composite-id>


I made a CompositeKey class with the two key fields in it (though ultimately I need a more general solution). But I find I can still put the key fields straight into the entity Map (which is what I orignally wanted :) and successfully session.load the entity.

In fact session.load doesn't seem to work when I populate the fields in the CompositeKey instance specified in the hbm above.

All a bit confusing; anyone else got any good examples?

---------------

Meanwhile I've downloaded & built the hibernate3 from CVS but the latest files are from March 7th, and I still get my problem from the initial test case.

Does anyone know what else I need to do in order to pick up the latest? Synchronising / updating etc from Eclipse CVS don't seem to get any more recent files.

Thanks again,
Jeremy


Top
 Profile  
 
 Post subject: what I should be doing is...
PostPosted: Thu Mar 10, 2005 11:45 am 
Newbie

Joined: Thu Jan 08, 2004 11:54 am
Posts: 10
It works better if I use a Map for the id :)

I have to specify the type of the pk fields in the composite-id / key-property.

Code:
<composite-id name="id" class="java.util.Map" >
      <key-property name="key1" type="long" column="akey1" />
      <key-property name="key2" type="long" column="akey2" />
</composite-id>


My objects now look like this:

HashMap entity
{
"id" -> HashMap { "key1" -> [Long 123], "key2" -> [Long 456] },
"otherProperty" -> "val1",
"etc" ...
}

I'm still interested in the answer to the CVS question BTW...


Top
 Profile  
 
 Post subject: CVS now works thanks
PostPosted: Thu Mar 10, 2005 6:38 pm 
Newbie

Joined: Thu Jan 08, 2004 11:54 am
Posts: 10
The latest refresh from CVS now works with my test case, many thanks.
(DefaultFlushEntityEventListener.java V1.7)


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