Multiple Collections in class, not using discriminator value?

52 views
Skip to first unread message

Jon Stelly

unread,
Nov 19, 2008, 6:45:56 PM11/19/08
to nhusers
Hi,

I think I've run into a bug in 2.0.1, but I haven't found anything in
Jira and wanted to ask here before I posted a bug to make sure I'm not
just doing something stupid. I've got a class hierarchy with a table
per hierarchy mapping, and a class of type C that has 2 collections,
One of type IList<D> and one of type IList<E>. C, D, and E are all
derived from a type A and are all mapped as subclasses of A like in
the mapping below.

NHibernate doesn't seem to generate the right query for retrieving the
Ds and Es collections. I would expect those loads to have a WHERE
clause using the discriminator column and value, "WHERE
EntityType='D'", right? But it's not doing that. The query it
generates for loading the Ds collection (I can get this if I unmap the
Es collection), looks like this:

SELECT ds0_.ParentID as ParentID1_, ds0_.ID as ID1_, ds0_.ID as
ID0_0_, ds0_.ParentID as ParentID0_0_ FROM A ds0_ WHERE
ds0_.ParentID=@p0

And NHibernate loads the instance of type D as an object of type E,
which causes an exception (also pasted below). I can add a ...
where="EntityType='D'" attribute to the Ds bag mapping and then
everything loads correctly, but that doesn't seem right to me.

Am I doing something wrong or is this a real bug? Also, if it is a
real bug, can someone just point me in the direction of where to
look? I'd be happy to try my hand at fixing the issue and submitting
a patch but I'm just starting to debug through the NHibernate code.

Thanks. Also, here are the mappings, a class diagram, and then the
exception I am seeing:

-----------------------------------------------------------------------------------------------------
<hibernate-mapping default-lazy="false" namespace="NHTest"
assembly="NHTest" xmlns="urn:nhibernate-mapping-2.2">

<class name="A" abstract="true">
<id name="ID">
<generator class="guid.comb" />
</id>
<discriminator column="EntityType" length="64"/>
</class>

<subclass name="B" discriminator-value="B" extends="NHTest.A,
NHTest"/>

<subclass name="C" discriminator-value="C" extends="NHTest.A,
NHTest">
<many-to-one name="Parent" column="ParentID" class="NHTest.B,
NHTest"/>
<bag name="Ds" cascade="all-delete-orphan" inverse="true">
<key column="ParentID" foreign-key="FK_ParentID" />
<one-to-many class="NHTest.D, NHTest" />
</bag>
<bag name="Es" cascade="all-delete-orphan" inverse="true">
<key column="ParentID" foreign-key="FK_ParentID" />
<one-to-many class="NHTest.E, NHTest" />
</bag>
</subclass>

<subclass name="D" discriminator-value="D" extends="NHTest.A,
NHTest">
<many-to-one name="Parent" column="ParentID" class="NHTest.C,
NHTest"/>
</subclass>

<subclass name="E" discriminator-value="E" extends="NHTest.A,
NHTest">
<many-to-one name="Parent" column="ParentID" class="NHTest.C,
NHTest"/>
</subclass>

</hibernate-mapping>
-----------------------------------------------------------------------------------------------------

The class diagram for these classes looks like this:
-----------------------------------------------------------------------------------------------------
http://www.jonstelly.com/development/nhibernate-collection-issue/Model.png
-----------------------------------------------------------------------------------------------------

And the exception I get when trying to do a "FROM A" HQL query looks
like this:
-----------------------------------------------------------------------------------------------------
2008-11-19 17:17:20,562 [1] INFO NHibernate.Loader.Loader [(null)] -
select a0_.ID as ID0_, a0_.ParentID as ParentID0_, a0_.EntityType as
EntityType0_ from A a0_ NHibernate: select a0_.ID as ID0_,
a0_.ParentID as ParentID0_, a0_.EntityType as EntityType0_ from A a0_
2008-11-19 17:17:20,656 [1] INFO NHibernate.Loader.Loader [(null)] -
SELECT es0_.ParentID as ParentID1_, es0_.ID as ID1_, es0_.ID as
ID0_0_, es0_.ParentID as ParentID0_0_ FROM A es0_ WHERE
es0_.ParentID=@p0 NHibernate: SELECT es0_.ParentID as ParentID1_,
es0_.ID as ID1_, es0_.ID as ID0_0_, es0_.ParentID as ParentID0_0_ FROM
A es0_ WHERE es0_.ParentID=@p0; @p0 = 'c603975f-7e8c-44e1-
bdb2-9b59011ce9b5'
Unhandled Exception: NHibernate.WrongClassException: Object with id:
a024b45b-6a0b-4772-bef1-9b59011ce9c3 was not of the specified
subclass: NHTest.E (loading object was of wrong class [NHTest.D])
at NHibernate.Loader.Loader.InstanceAlreadyLoaded(IDataReader rs,
Int32 i, IEntityPersister persister, EntityKey key, Object obj,
LockMode lockMode, ISessionImplementor session)
at NHibernate.Loader.Loader.GetRow(IDataReader rs, ILoadable[]
persisters, EntityKey[] keys, Object optionalObject, EntityKey
optionalObjectKey, LockMode[] lockModes, IList hydratedObjects,
ISessionImplementor session)
at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader
resultSet, ISessionImplementor session, QueryParameters
queryParameters, LockMode[] lockModeArray, EntityKey
optionalObjectKey, IList hydratedObjects, EntityKey[] keys,
BooleanreturnProxies)
at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session,
QueryParameters queryParameters, Boolean returnProxies)
at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections
(ISessionImplementor session, QueryParameters queryParameters, Boolean
returnProxies)
at NHibernate.Loader.Loader.LoadCollection(ISessionImplementor
session, Object id, IType type)
at NHibernate.Loader.Collection.CollectionLoader.Initialize(Object
id, ISessionImplementor session)
at
NHibernate.Persister.Collection.AbstractCollectionPersister.Initialize
(Object key, ISessionImplementor session)
at
NHibernate.Event.Default.DefaultInitializeCollectionEventListener.OnInitializeCollection
(InitializeCollectionEvent event)
at NHibernate.Impl.SessionImpl.InitializeCollection
(IPersistentCollection collection, Boolean writing)
at
NHibernate.Collection.AbstractPersistentCollection.ForceInitialization
()
at
NHibernate.Engine.StatefulPersistenceContext.InitializeNonLazyCollections
()
at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections
(ISessionImplementor session, QueryParameters queryParameters, Boolean
returnProxies)
at NHibernate.Loader.Loader.DoList(ISessionImplementor session,
QueryParameters queryParameters)
at NHibernate.Loader.Loader.ListIgnoreQueryCache
(ISessionImplementor session, QueryParameters queryParameters)
at NHibernate.Loader.Loader.List(ISessionImplementor session,
QueryParameters queryParameters, ISet`1 querySpaces, IType[]
resultTypes)
at NHibernate.Hql.Classic.QueryTranslator.List(ISessionImplementor
session, QueryParameters queryParameters)
at NHibernate.Engine.Query.HQLQueryPlan.PerformList(QueryParameters
queryParameters, ISessionImplementor session, IList results)
at NHibernate.Impl.SessionImpl.List(String query, QueryParameters
queryParameters, IList results)
at NHibernate.Impl.SessionImpl.List[T](String query,
QueryParameters parameters)
at NHibernate.Impl.QueryImpl.List[T]()
at NHTest.Program.Main(String[] args) in C:\Projects\NHTest\NHTest
\Program.cs:line 45

Jon Stelly

unread,
Nov 19, 2008, 8:06:30 PM11/19/08
to nhusers
As an update, I made the following change and the discriminator is
added to the WHERE clause for loading the Ds and Es collections. All
of my other classes, mappings and queries seem to work. I'm going to
do some more testing on this and try and run the NHibernate unit tests
against this change, then I'll probably open up a JIRA ticket later.


Index: SingleTableEntityPersister.cs
===================================================================
--- SingleTableEntityPersister.cs (revision 3917)
+++ SingleTableEntityPersister.cs (working copy)
@@ -522,7 +522,7 @@

public override string OneToManyFilterFragment(string alias)
{
- return forceDiscriminator ? DiscriminatorFilterFragment(alias) :
string.Empty;
+ return DiscriminatorFilterFragment(alias);
}

private string DiscriminatorFilterFragment(string alias)
Reply all
Reply to author
Forward
0 new messages