I have two tables each mapped to several classes using the table-per-class-hierarchy strategy. the tables are:
Users (UserId, RoleName, ...) where RoleName is the discriminator (values "advertiser", "publisher" etc)
Relationships (RelationshipId, RelationshipType, AdvertiserId, CampaignId, PublisherId, ...) where RelationshipType is the discriminator (values "A", "C", "P" etc)
the class hierarchy is:
User > AdvertiserUser, PublisherUser, etc
Relationship > AdvertiserRelationship, CampaignRelationship, PublisherRelationship, etc
AdvertiserUser has a one-to-one to AdvertiserRelationship and a one-to-many to CampaignRelationship.
AdvertiserRelationship has a many-to-one to AdvertiserUser.
i'm using Session.get to retrieve the instance of AdvertiserUser.class for a specified userId. this method is throwing an exception with the message "More than one row with the given identifier
was found: 14, for class: com.massive.adserver.user.AdvertiserRelationship".
the generated SQL (as taken from the mysql query log) is:
Code:
select advertiser0_.RelationshipId as Relation1_0_, advertiser0_.AdvertiserId as Advertis4_0_, advertiser0_.UserId as UserId0_, advertiser0_.perms as perms0_ from Relationships advertiser0_ where advertiser0_.UserId=14
running that query manually returns:
Code:
+--------------+--------------+----------+---------+
| Relation1_0_ | Advertis4_0_ | UserId0_ | perms0_ |
+--------------+--------------+----------+---------+
| 13 | 23 | 14 | 0 |
| 15 | NULL | 14 | 16 |
+--------------+--------------+----------+---------+
2 rows in set (1.35 sec)
the previous query to this one is against the Users table as expected.
question #1: why isn't the discriminator column included in the query? one would think Hibernate would examine it and throw away any rows that don't have RelationshipType="A" when loading the AdvertiserRelationship for the AdvertiserUser, and similarly for rows with RelationshipType="C" when loading the CampaignRelationships.
question #2: what do i do to make this work properly?
Hibernate version: 2.1.4
Mapping documents:User.hbm.xml:
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="com.massive.adserver.user.User"
table="Users"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="id"
type="integer"
unsaved-value="null"
>
<column
name="UserId"
not-null="true"
sql-type="integer"
/>
<generator class="native">
</generator>
</id>
<discriminator
column="RoleName"
type="string"
/>
<property
name="roleName"
type="java.lang.String"
update="false"
insert="false"
access="property"
column="RoleName"
length="20"
not-null="true"
/>
<subclass
name="com.massive.adserver.user.AdvertiserUser"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="advertiser"
>
<one-to-one
name="advertiserRelationship"
class="com.massive.adserver.user.AdvertiserRelationship"
cascade="all"
outer-join="auto"
constrained="false"
property-ref="advertiserUser"
/>
<set
name="campaignRelationships"
lazy="false"
inverse="true"
cascade="all-delete-orphan"
sort="unsorted"
>
<key
column="CampaignId"
>
</key>
<one-to-many
class="com.massive.adserver.user.CampaignRelationship"
/>
</set>
</subclass>
</class>
</hibernate-mapping>
Relationship.hbm.xml:
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="com.massive.adserver.user.Relationship"
table="Relationships"
dynamic-update="false"
dynamic-insert="false"
>
<id
name="id"
type="integer"
unsaved-value="null"
>
<column
name="RelationshipId"
not-null="true"
sql-type="integer"
/>
<generator class="native">
</generator>
</id>
<discriminator
column="RelationshipType"
type="string"
/>
<subclass
name="com.massive.adserver.user.AdvertiserRelationship"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="A"
>
<property
name="advertiserId"
type="java.lang.Integer"
update="true"
insert="true"
access="property"
column="AdvertiserId"
not-null="true"
/>
<many-to-one
name="advertiserUser"
class="com.massive.adserver.user.AdvertiserUser"
cascade="none"
outer-join="auto"
update="true"
insert="true"
access="property"
column="UserId"
not-null="true"
/>
</subclass>
<subclass
name="com.massive.adserver.user.CampaignRelationship"
dynamic-update="false"
dynamic-insert="false"
discriminator-value="C"
>
<property
name="campaignId"
type="java.lang.Integer"
update="true"
insert="true"
access="property"
column="CampaignId"
not-null="true"
/>
</subclass>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
// called from next method
public Session currentSession(boolean withTx)
throws MassiveException {
try {
return SessionManager.getSession(dataSourceName,
new PersistentInterceptor(),
withTx);
} catch (HibernateException e) {
log.error("unable to get Hibernate session for datasource [" +
dataSourceName + "]", e);
throw new MassiveException("unable to get Hibernate " +
"session for datasource [" +
dataSourceName + "]", e);
}
}
// called from next method
private User getUser(Integer userId, Class userClass, boolean withInactive)
throws UserNotFoundException, MassiveException {
try {
Session session = currentSession();
if (log.isDebugEnabled()) {
log.debug("getting user [" + userId + "]");
}
User user = (User) session.get(userClass, userId);
if (user == null) {
throw new UserNotFoundException(userId);
}
if (! withInactive && ! user.getActive().booleanValue()) {
return null;
}
return user;
} catch (HibernateException e) {
log.error("unable to get user [" + userId +"]", e);
killCurrentSession();
throw new MassiveException("unable to get user [" +
userId + "]", e);
}
}
public AdvertiserUser getAdvertiserUser(Integer userId,
boolean withInactive)
throws UserNotFoundException, MassiveException {
return (AdvertiserUser) getUser(userId, AdvertiserUser.class,
withInactive);
}
Full stack trace of any exception that occurs:Code:
net.sf.hibernate.HibernateException: More than one row with the given identifier was found: 14, for class: com.massive.adserver.user.AdvertiserRelationship at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:71) at net.sf.hibernate.loader.EntityLoader.loadByUniqueKey(EntityLoader.java:55) at net.sf.hibernate.persister.AbstractEntityPersister.loadByUniqueKey(AbstractEntityPersister.java:1103) at net.sf.hibernate.impl.SessionImpl.loadByUniqueKey(SessionImpl.java:3844) at net.sf.hibernate.type.EntityType.resolveIdentifier(EntityType.java:207) at net.sf.hibernate.impl.SessionImpl.initializeEntity(SessionImpl.java:2201) at net.sf.hibernate.loader.Loader.doQuery(Loader.java:240) at net.sf.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:133) at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:836) at net.sf.hibernate.loader.Loader.loadEntity(Loader.java:856) at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:59) at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:51) at net.sf.hibernate.persister.EntityPersister.load(EntityPersister.java:419) at net.sf.hibernate.impl.SessionImpl.doLoad(SessionImpl.java:2113) at net.sf.hibernate.impl.SessionImpl.doLoadByClass(SessionImpl.java:1987) at net.sf.hibernate.impl.SessionImpl.get(SessionImpl.java:1923) at com.massive.adserver.user.UserManager.getUser(UserManager.java:250) at com.massive.adserver.user.UserManager.getUser(UserManager.java:278) at com.massive.adserver.partner.delegate.SysAdminDelegate.getUser(SysAdminDelegate.java:166) at com.massive.adserver.partner.action.sysadmin.user.UserEditPrepareAction.getUser(UserEditPrepareAction.java:67) at com.massive.adserver.partner.action.sysadmin.user.UserEditPrepareAction.prepare(UserEditPrepareAction.java:52) at com.massive.action.MassivePrepareAction.execute(MassivePrepareAction.java:42) at com.massive.adserver.partner.action.AdServerPrepareAction.execute(AdServerPrepareAction.java:73) at org.apache.struts.action.RequestProcessor.processActionPerform(RequestProcessor.java:484) at org.apache.struts.action.RequestProcessor.process(RequestProcessor.java:274) at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1482) at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:507) at javax.servlet.http.HttpServlet.service(HttpServlet.java:697) at javax.servlet.http.HttpServlet.service(HttpServlet.java:810) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:237) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157) at com.massive.adserver.partner.filter.LoginFilter.doFilter(LoginFilter.java:99) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157) at com.massive.adserver.hibernate.HibernateFilter.doFilter(HibernateFilter.java:95) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:186) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:157) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:214) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520) at org.apache.catalina.core.StandardContextValve.invokeInternal(StandardContextValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:152) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:540) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:117) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:102) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.core.StandardValveContext.invokeNext(StandardValveContext.java:104) at org.apache.catalina.core.StandardPipeline.invoke(StandardPipeline.java:520) at org.apache.catalina.core.ContainerBase.invoke(ContainerBase.java:929) at org.apache.coyote.tomcat5.CoyoteAdapter.service(CoyoteAdapter.java:160) at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:793) at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.processConnection(Http11Protocol.java:702) at org.apache.tomcat.util.net.TcpWorkerThread.runIt(PoolTcpEndpoint.java:571) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:644) at java.lang.Thread.run(Thread.java:552)
Name and version of the database you are using:Code:
bcm@vrock:~/ai/massive > mysqladmin version
mysqladmin Ver 8.40 Distrib 4.0.18, for apple-darwin6.8 on powerpc
The generated SQL (show_sql=true):Code:
select advertiser0_.RelationshipId as Relation1_0_, advertiser0_.AdvertiserId as Advertis4_0_, advertiser0_.UserId as UserId0_, advertiser0_.perms as perms0_ from Relationships advertiser0_ where advertiser0_.UserId=14
Debug level Hibernate log excerpt:Code:
2005-01-18 17:17:26,277 DEBUG [SessionFactoryImpl] instantiated session factory
2005-01-18 17:19:09,811 DEBUG [SysAdminDelegate] getting user [14]
2005-01-18 17:19:10,026 DEBUG [SessionImpl] opened session
2005-01-18 17:19:10,027 DEBUG [UserManager] getting user [14]
2005-01-18 17:19:10,044 DEBUG [SessionImpl] loading [com.massive.adserver.user.User#14]
2005-01-18 17:19:10,045 DEBUG [SessionImpl] attempting to resolve [com.massive.adserver.user.User#14]
2005-01-18 17:19:10,049 DEBUG [SessionImpl] object not resolved in any cache [com.massive.adserver.user.User#14]
2005-01-18 17:19:10,050 DEBUG [EntityPersister] Materializing entity: [com.massive.adserver.user.User#14]
2005-01-18 17:19:10,055 DEBUG [BatcherImpl] about to open: 0 open PreparedStatements, 0 open ResultSets
2005-01-18 17:19:10,057 DEBUG [SQL] select user0_.UserId as UserId0_, user0_.RoleName as RoleName0_, user0_.FirstName as FirstName0_, user0_.LastName as LastName0_, user0_.MiddleName as MiddleName0_, user0_.Email as Email0_, user0_.PhoneWork as PhoneWork0_, user0_.PhoneFax as PhoneFax0_, user0_.PhoneMobile as PhoneMob9_0_, user0_.UserName as UserName0_, user0_.Password as Password0_, user0_.IPAddress as IPAddress0_, user0_.Active as Active0_, user0_.DateCreated as DateCre14_0_, user0_.DateModified as DateMod15_0_ from Users user0_ where user0_.UserId=?
2005-01-18 17:19:10,057 DEBUG [BatcherImpl] preparing statement
2005-01-18 17:19:10,058 DEBUG [IntegerType] binding '14' to parameter: 1
2005-01-18 17:19:10,062 DEBUG [Loader] processing result set
2005-01-18 17:19:10,063 DEBUG [Loader] result row: 14
2005-01-18 17:19:10,064 DEBUG [StringType] returning 'advertiser' as column: RoleName0_
2005-01-18 17:19:10,065 DEBUG [Loader] Initializing object from ResultSet: 14
2005-01-18 17:19:10,068 DEBUG [Loader] Hydrating entity: com.massive.adserver.user.AdvertiserUser#14
2005-01-18 17:19:10,072 DEBUG [StringType] returning 'Tuggy' as column: FirstName0_
2005-01-18 17:19:10,072 DEBUG [StringType] returning 'Jonez' as column: LastName0_
2005-01-18 17:19:10,072 DEBUG [StringType] returning '' as column: MiddleName0_
2005-01-18 17:19:10,073 DEBUG [StringType] returning 'bcm@maz.org' as column: Email0_
2005-01-18 17:19:10,073 DEBUG [StringType] returning '' as column: PhoneWork0_
2005-01-18 17:19:10,073 DEBUG [StringType] returning '' as column: PhoneFax0_
2005-01-18 17:19:10,073 DEBUG [StringType] returning '' as column: PhoneMob9_0_
2005-01-18 17:19:10,074 DEBUG [StringType] returning 'tuggy' as column: UserName0_
2005-01-18 17:19:10,074 DEBUG [StringType] returning '49f68a5c8493ec2c0bf489821c21fc3b' as column: Password0_
2005-01-18 17:19:10,074 DEBUG [StringType] returning '127.0.0.1' as column: IPAddress0_
2005-01-18 17:19:10,074 DEBUG [StringType] returning 'advertiser' as column: RoleName0_
2005-01-18 17:19:10,075 DEBUG [BooleanType] returning 'true' as column: Active0_
2005-01-18 17:19:10,086 DEBUG [TimestampType] returning '12 January 2005 12:48:22' as column: DateCre14_0_
2005-01-18 17:19:10,087 DEBUG [TimestampType] returning '18 January 2005 15:55:37' as column: DateMod15_0_
2005-01-18 17:19:10,116 DEBUG [Loader] done processing result set (1 rows)
2005-01-18 17:19:10,117 DEBUG [BatcherImpl] done closing: 0 open PreparedStatements, 0 open ResultSets
2005-01-18 17:19:10,117 DEBUG [BatcherImpl] closing statement
2005-01-18 17:19:10,117 DEBUG [Loader] total objects hydrated: 1
2005-01-18 17:19:10,118 DEBUG [SessionImpl] resolving associations for [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,118 DEBUG [BatcherImpl] about to open: 0 open PreparedStatements, 0 open ResultSets
2005-01-18 17:19:10,119 DEBUG [SQL] select advertiser0_.RelationshipId as Relation1_0_, advertiser0_.AdvertiserId as Advertis4_0_, advertiser0_.UserId as UserId0_, advertiser0_.perms as perms0_ from Relationships advertiser0_ where advertiser0_.UserId=?
2005-01-18 17:19:10,119 DEBUG [BatcherImpl] preparing statement
2005-01-18 17:19:10,119 DEBUG [IntegerType] binding '14' to parameter: 1
2005-01-18 17:19:10,155 DEBUG [Loader] processing result set
2005-01-18 17:19:10,156 DEBUG [IntegerType] returning '13' as column: Relation1_0_
2005-01-18 17:19:10,156 DEBUG [Loader] result row: 13
2005-01-18 17:19:10,156 DEBUG [Loader] Initializing object from ResultSet: 13
2005-01-18 17:19:10,157 DEBUG [Loader] Hydrating entity: com.massive.adserver.user.AdvertiserRelationship#13
2005-01-18 17:19:10,157 DEBUG [IntegerType] returning '23' as column: Advertis4_0_
2005-01-18 17:19:10,157 DEBUG [IntegerType] returning '14' as column: UserId0_
2005-01-18 17:19:10,158 DEBUG [IntegerType] returning '0' as column: perms0_
2005-01-18 17:19:10,158 DEBUG [IntegerType] returning '15' as column: Relation1_0_
2005-01-18 17:19:10,158 DEBUG [Loader] result row: 15
2005-01-18 17:19:10,158 DEBUG [Loader] Initializing object from ResultSet: 15
2005-01-18 17:19:10,159 DEBUG [Loader] Hydrating entity: com.massive.adserver.user.AdvertiserRelationship#15
2005-01-18 17:19:10,159 DEBUG [IntegerType] returning null as column: Advertis4_0_
2005-01-18 17:19:10,159 DEBUG [IntegerType] returning '14' as column: UserId0_
2005-01-18 17:19:10,159 DEBUG [IntegerType] returning '16' as column: perms0_
2005-01-18 17:19:10,160 DEBUG [Loader] done processing result set (2 rows)
2005-01-18 17:19:10,160 DEBUG [BatcherImpl] done closing: 0 open PreparedStatements, 0 open ResultSets
2005-01-18 17:19:10,160 DEBUG [BatcherImpl] closing statement
2005-01-18 17:19:10,160 DEBUG [Loader] total objects hydrated: 2
2005-01-18 17:19:10,161 DEBUG [SessionImpl] resolving associations for [com.massive.adserver.user.AdvertiserRelationship#13]
2005-01-18 17:19:10,161 DEBUG [SessionImpl] loading [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,161 DEBUG [SessionImpl] attempting to resolve [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,162 DEBUG [SessionImpl] resolved object in session cache [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,164 DEBUG [SessionImpl] done materializing entity [com.massive.adserver.user.AdvertiserRelationship#13]
2005-01-18 17:19:10,165 DEBUG [SessionImpl] resolving associations for [com.massive.adserver.user.AdvertiserRelationship#15]
2005-01-18 17:19:10,165 DEBUG [SessionImpl] loading [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,167 DEBUG [SessionImpl] attempting to resolve [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,167 DEBUG [SessionImpl] resolved object in session cache [com.massive.adserver.user.AdvertiserUser#14]
2005-01-18 17:19:10,167 DEBUG [SessionImpl] done materializing entity [com.massive.adserver.user.AdvertiserRelationship#15]
2005-01-18 17:19:10,180 ERROR [UserManager] unable to get user [14]
net.sf.hibernate.HibernateException: More than one row with the given identifier was found: 14, for class: com.massive.adserver.user.AdvertiserRelationship
at net.sf.hibernate.loader.EntityLoader.load(EntityLoader.java:71)
at net.sf.hibernate.loader.EntityLoader.loadByUniqueKey(EntityLoader.java:55)