-->
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.  [ 1 post ] 
Author Message
 Post subject: Composite-id with subclass throws an exception when flushing
PostPosted: Thu Feb 17, 2005 5:37 am 
Newbie

Joined: Fri Aug 20, 2004 8:37 am
Posts: 2
Hibernate version: 2.1.6

Mapping documents: (simplified)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping default-cascade="none" schema="D" package="com.maquette.model.plc.common.dt">
<class name="Adr" table="adr">
<composite-id>
<key-property column="numcomp" name="numcomp" type="int" />
<key-property column="numadr" name="numadr" type="int" />
</composite-id>
<discriminator column="type" type="string" />
<property column="adress" name="adresse" type="string" />
<version name="admstamp" />
<subclass name="Adr$WAdr" discriminator-value="W">
<property column="numw" name="numw" type="int" />
</subclass>
</class>
</hibernate-mapping>

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

I first execute an HQL query which only reads Adr$Wadr objects. The following exception is thrown when I execute another HQL query which reads some other objects.

First query: "from Adr$Wadr adr where adr.numcomp = :numcomp"
Second query: "from Country c where c.numc = :numc"

Full stack trace of any exception that occurs:

net.sf.hibernate.HibernateException: identifier of an instance of com.maquette.model.plc.common.dt.Adr$WAdr altered from com.maquette.model.plc.common.dt.Adr@5f5ef3a to com.maquette.model.plc.common.dt.Adr$WAdr@5f5ef3a
at net.sf.hibernate.impl.SessionImpl.checkId(SessionImpl.java:2671)
at net.sf.hibernate.impl.SessionImpl.flushEntity(SessionImpl.java:2494)
at net.sf.hibernate.impl.SessionImpl.flushEntities(SessionImpl.java:2487)
at net.sf.hibernate.impl.SessionImpl.flushEverything(SessionImpl.java:2289)
at net.sf.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1834)
at net.sf.hibernate.impl.SessionImpl.getQueries(SessionImpl.java:1597)
at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:1533)
at net.sf.hibernate.impl.QueryImpl.list(QueryImpl.java:39)
at com.maquette.model.services.common.dt.CountryDAOHQLImpl.getCountry(CountryDAOHQLImpl.java:27)
... 12 more

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

Adr is a true POJO. I declared its subclass WAdr as a public static inner class but I think this has no incidence on this issue.

I tried to debug a little so I can give a beginning of explanation.

When I call list method on my second Query object, Hibernate decides to flush. In SessionImpl, it calls autoFlushIfRequired, which ends with calling flushEntity for my Adr$Wadr entities. At this point Hibernate checks if my entity is dirty with checkId method.

checkId method compares the previous stored id of the entity with the "current identifier" using the getIdentifier method of the class persister of my entity. As the identifier is embedded, it just returns the instance of my entity. This instance is a Adr$Wadr thus the serialized "current identifier" is "com.maquette.model.plc.common.dt.Adr$WAdr@5f5ef3a".

Nevertheless the stored id of the entity is slightly different. When I called list method on my first Query, it indirectly called getRowFromResultSet of Loader which needed to compute the keys of my entities. Thus it called getKeyFromResultSet which determined the type of the key using getIdentifierType method of the class persister of my entity (Hibernate already knew here that my entity was a Adr$Wadr and so the class persister was Adr$Wadr persister and not Adr persister). The point is that this method returns a ComponentType for com.maquette.model.plc.common.dt.Adr class and not com.maquette.model.plc.common.dt.Adr$Wadr class. Then Hibernate retrieves an instance of that class and it returns an Adr object. Thus the first serialized identifier was "com.maquette.model.plc.common.dt.Adr@5f5ef3a".

So I wonder if the returned ComponentType object is right. Entity persisters are based upon mapping files. When Hibernate finds a "subclass" node in the mapping files, it calls handleSubclass of Binder. A new Subclass object based upon its "root class" is created. The getIdentifier method of Subclass just returns the identifier of its "root class". This is fair when you use a simple id, or a composite-id with an explicit type. Nevertheless this seems to be problematic with embedded composite-id. I think getIdentifier method of Subclass should not always return the identifier of its "root class".

I'd like to use an embedded identifier because it allows me to have all the properties inside the same object. I use a legacy database and the composite keys are business keys. Thus I think it's cleaner to make my objects real POJOs with key properties directly inside of them.

I hope my explanations are understandable (up to now I'm not an Hibernate expert and I might tell nonsense...) Please tell me if you consider this could be a bug and what should be done.


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

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.