Hi,
I'm having some troubles with mapping/querying connected to inheritance.
I have an abstract superclass
HCP and two classes extending it: the
Doctor and the Insitution class. I mapped them in one file called HCP.hbm.xml with the subclass-tag, using the one-table-per-class-hierarchry-strategy as suggested in the documentation.
Inserting new objects of type Doctor works fine. When I want to query for existing Doctor-Classes by using the Criteria-API, I am not able to get the instances loaded. What I do get is the following exception:
Code:
net.sf.hibernate.WrongClassException: Object with id: 13 was not of the specifie
d subclass: de.akteonline.model.contact.Doctor (loaded object was of wrong class
)
at net.sf.hibernate.loader.Loader.instanceAlreadyLoaded(Loader.java:535)
at net.sf.hibernate.loader.Loader.getRow(Loader.java:502)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:218)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections
(Loader.java:138)
at net.sf.hibernate.loader.Loader.doList(Loader.java:1063)
at net.sf.hibernate.loader.Loader.list(Loader.java:1054)
at net.sf.hibernate.loader.CriteriaLoader.list(CriteriaLoader.java:118)
at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:3660)
at net.sf.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:238)
The database shows the Doctor previously created with the discriminator-value set correctly:
Code:
select * from HCP;
id HCP_TYPE field ....
13 DOCTOR <NULL> ....
What I want is to get only the subclasses of type Doctor when I do a Criteria-Query with that specific subclass. In the example I used Expression.notNull("surName").
I have searched the Web, forums and Mailinglist and here is what I have tried already:
- mapping with the "polymorphism=explicit" attribute
- querying using the superclass, then iterating over results and picking the subclasses I want: this is not possible with Criteria because Hibernate then cannot find the subclass properties I am querying for obviously
Please find all the detailed information in the following section.
Any help would be greatly appriciated.
Thank you.
Sven Tessmann
Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelpHibernate version: 2.1.18
Mapping documents:Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="de.akteonline.model.contact.HCP" discriminator-value="HCP">
<id name="id" type="int">
<generator class="native" />
</id>
<discriminator column="HCP_TYPE" type="string"/>
<list name="contacts">
<key column="HCP_ID"/>
<index column="HCP_IX" />
<one-to-many class="de.akteonline.model.contact.ContactData" />
</list>
<subclass name="de.akteonline.model.contact.Doctor" discriminator-value="DOCTOR">
<property name="field" />
<property name="firstName" />
<property name="formOfAdress" />
<one-to-one name="institution" />
<property name="otherFirstNames" />
<property name="phoneExtension" />
<property name="surName" />
<property name="titles" />
</subclass>
<subclass name="de.akteonline.model.contact.Institution" discriminator-value="INSTITUTION">
<property name="branch" />
<property name="department" />
<property name="name" />
<property name="secondDepartment" />
</subclass>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
public <T> Collection<T> getPersistentObjects(T type, Criterion criterion) throws DataManagerException {
logger.debug("entering <getPersistentObjects> with type="
+type.getClass().toString()+
"and criterion="+criterion.toString());
/* list holds matching objects*/
Collection<T> list = null;
try {
/* initialize criteria on current session */
Criteria criteria = HibernateUtil.currentSession()
.createCriteria(type.getClass());
/* add the passed criterion*/
criteria.add(criterion);
Transaction tx = HibernateUtil.currentSession()
.beginTransaction();
/* start the query */
list = (List<T>)criteria.list();
/* initialize the list for now to avoid lazy loading funny stuff ;-) */
int size = list.size();
tx.commit();
} catch (HibernateException e) {
logger.error("hibernate error during object retrieval.");
e.printStackTrace();
throw new DataManagerException("hibernate error.", e.getCause());
} finally{
try {
HibernateUtil.closeSession();
} catch (HibernateException e) {
logger.error("hibernate error during session close.");
throw new DataManagerException("hibernate error.", e.getCause());
}
} // finally
/* return the list of matching objects*/
return list;
} // getPersistantObjects
Full stack trace of any exception that occurs:Code:
net.sf.hibernate.WrongClassException: Object with id: 13 was not of the specifie
d subclass: de.akteonline.model.contact.Doctor (loaded object was of wrong class
)
at net.sf.hibernate.loader.Loader.instanceAlreadyLoaded(Loader.java:535)
at net.sf.hibernate.loader.Loader.getRow(Loader.java:502)
at net.sf.hibernate.loader.Loader.getRowFromResultSet(Loader.java:218)
at net.sf.hibernate.loader.Loader.doQuery(Loader.java:285)
at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections
(Loader.java:138)
at net.sf.hibernate.loader.Loader.doList(Loader.java:1063)
at net.sf.hibernate.loader.Loader.list(Loader.java:1054)
at net.sf.hibernate.loader.CriteriaLoader.list(CriteriaLoader.java:118)
at net.sf.hibernate.impl.SessionImpl.find(SessionImpl.java:3660)
at net.sf.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:238)
at de.akteonline.core.service.DataManager.getPersistentObjects(DataManag
er.java:178)
Name and version of the database you are using:MySQL 4.0.x
The generated SQL (show_sql=true):Code:
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.SQL - select this_.id as id1_, this_.field as field2_1_, this_.firstName as firstName2_1_, this_.formOfAdress as formOfAd5_2_1_, this_.otherFirstNames as otherFir6_2_1_, this_.phoneExtension as phoneExt7_2_1_, this_.surName as surName2_1_, this_.titles as titles2_1_, institutio2_.id as id0_, institutio2_.branch as branch2_0_, institutio2_.department as department2_0_, institutio2_.name as name2_0_, institutio2_.secondDepartment as secondD13_2_0_ from HCP this_ left outer join HCP institutio2_ on this_.id=institutio2_.id where this_.HCP_TYPE='DOCTOR' and this_.surName is not null
Debug level Hibernate log excerpt:Code:
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.impl.SessionImpl - opened session at timestamp: 4575026430939136
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.transaction.JDBCTransaction - begin
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.jdbc.ConnectionManager - opening JDBC connection
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.connection.DriverManagerConnectionProvider - total checked-out connections: 0
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.connection.DriverManagerConnectionProvider - using pooled JDBC connection, pool size: 0
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.transaction.JDBCTransaction - current autocommit status: false
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.jdbc.AbstractBatcher - about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.SQL - select this_.id as id1_, this_.field as field2_1_, this_.firstName as firstName2_1_, this_.formOfAdress as formOfAd5_2_1_, this_.otherFirstNames as otherFir6_2_1_, this_.phoneExtension as phoneExt7_2_1_, this_.surName as surName2_1_, this_.titles as titles2_1_, institutio2_.id as id0_, institutio2_.branch as branch2_0_, institutio2_.department as department2_0_, institutio2_.name as name2_0_, institutio2_.secondDepartment as secondD13_2_0_ from HCP this_ left outer join HCP institutio2_ on this_.id=institutio2_.id where this_.HCP_TYPE='DOCTOR' and this_.surName is not null
17:50:12,241 DEBUG http-8080-Processor25 org.hibernate.jdbc.AbstractBatcher - preparing statement
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.jdbc.AbstractBatcher - about to open ResultSet (open ResultSets: 0, globally: 0)
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.loader.Loader - processing result set
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.loader.Loader - result set row: 0
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.type.IntegerType - returning '2' as column: id0_
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.type.IntegerType - returning '2' as column: id1_
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.loader.Loader - result row: EntityKey[de.akteonline.model.contact.Institution#2], EntityKey[de.akteonline.model.contact.Doctor#2]
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.loader.Loader - Initializing object from ResultSet: [de.akteonline.model.contact.Institution#2]
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.persister.entity.BasicEntityPersister - Hydrating entity: [de.akteonline.model.contact.Institution#2]
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.type.StringType - returning null as column: branch2_0_
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.type.StringType - returning null as column: department2_0_
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.type.StringType - returning null as column: name2_0_
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.type.StringType - returning null as column: secondD13_2_0_
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.jdbc.AbstractBatcher - about to close ResultSet (open ResultSets: 1, globally: 1)
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.jdbc.AbstractBatcher - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
17:50:12,342 DEBUG http-8080-Processor25 org.hibernate.jdbc.AbstractBatcher - closing statement
17:50:12,512 DEBUG http-8080-Processor25 org.hibernate.impl.SessionImpl - closing session
17:50:12,512 DEBUG http-8080-Processor25 org.hibernate.jdbc.ConnectionManager - closing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
17:50:12,512 DEBUG http-8080-Processor25 org.hibernate.connection.DriverManagerConnectionProvider - returning connection to pool, pool size: 1
17:50:12,702 DEBUG Finalizer org.hibernate.jdbc.ConnectionManager - running Session.finalize()