How can I eager-load a child collection mapped to a non-primary key in NHibernate 2.1.2?

Posted by David Rubin on Stack Overflow See other posts from Stack Overflow or by David Rubin
Published on 2010-05-27T19:09:30Z Indexed on 2010/05/27 19:11 UTC
Read the original article Hit count: 924

Hi,

I have two objects with a many-to-many relationship between them, as follows:

public class LeftHandSide
{
    public LeftHandSide()
    {
        Name = String.Empty;
        Rights = new HashSet<RightHandSide>();
    }

    public int Id { get; set; }
    public string Name { get; set; }
    public ICollection<RightHandSide> Rights { get; set; }
}

public class RightHandSide
{
    public RightHandSide()
    {
        OtherProp = String.Empty;
        Lefts = new HashSet<LeftHandSide>();
    }

    public int Id { get; set; }
    public string OtherProp { get; set; }
    public ICollection<LeftHandSide> Lefts { get; set; }
}

and I'm using a legacy database, so my mappings look like: Notice that LeftHandSide and RightHandSide are associated by a different column than RightHandSide's primary key.

<class name="LeftHandSide" table="[dbo].[lefts]" lazy="false">
    <id name="Id" column="ID" unsaved-value="0">
      <generator class="identity" />
    </id> 
    <property name="Name" not-null="true" />
    <set name="Rights" table="[dbo].[lefts2rights]">
        <key column="leftId" />
<!-- THIS IS THE IMPORTANT BIT: I MUST USE PROPERTY-REF -->
        <many-to-many class="RightHandSide" column="rightProp" property-ref="OtherProp" />
    </set>
</class>

<class name="RightHandSide" table="[dbo].[rights]" lazy="false">
    <id name="Id" column="id" unsaved-value="0">
        <generator class="identity" />
    </id>
    <property name="OtherProp" column="otherProp" />
    <set name="Lefts" table="[dbo].[lefts2rights]">
<!-- THIS IS THE IMPORTANT BIT: I MUST USE PROPERTY-REF -->
        <key column="rightProp" property-ref="OtherProp" />
        <many-to-many class="LeftHandSide" column="leftId" />
    </set>
</class>

The problem comes when I go to do a query:

LeftHandSide lhs = _session.CreateCriteria<LeftHandSide>()
                        .Add(Expression.IdEq(13))
                        .UniqueResult<LeftHandSide>();

works just fine. But

LeftHandSide lhs = _session.CreateCriteria<LeftHandSide>()
                        .Add(Expression.IdEq(13))
                        .SetFetchMode("Rights", FetchMode.Join)
                        .UniqueResult<LeftHandSide>();

throws an exception (see below). Interestingly,

RightHandSide rhs = _session.CreateCriteria<RightHandSide>()
                        .Add(Expression.IdEq(127))
                        .SetFetchMode("Lefts", FetchMode.Join)
                        .UniqueResult<RightHandSide>();

seems to be perfectly fine as well.

NHibernate.Exceptions.GenericADOException
Message: Error performing LoadByUniqueKey[SQL: SQL not available]
Source: NHibernate
StackTrace:
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Type\EntityType.cs(563,0): at NHibernate.Type.EntityType.LoadByUniqueKey(String entityName, String uniqueKeyPropertyName, Object key, ISessionImplementor session)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Type\EntityType.cs(428,0): at NHibernate.Type.EntityType.ResolveIdentifier(Object value, ISessionImplementor session, Object owner)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Type\EntityType.cs(300,0): at NHibernate.Type.EntityType.NullSafeGet(IDataReader rs, String[] names, ISessionImplementor session, Object owner)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Persister\Collection\AbstractCollectionPersister.cs(695,0): at NHibernate.Persister.Collection.AbstractCollectionPersister.ReadElement(IDataReader rs, Object owner, String[] aliases, ISessionImplementor session)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Collection\Generic\PersistentGenericSet.cs(54,0): at NHibernate.Collection.Generic.PersistentGenericSet`1.ReadFrom(IDataReader rs, ICollectionPersister role, ICollectionAliases descriptor, Object owner)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(706,0): at NHibernate.Loader.Loader.ReadCollectionElement(Object optionalOwner, Object optionalKey, ICollectionPersister persister, ICollectionAliases descriptor, IDataReader rs, ISessionImplementor session)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(385,0): at NHibernate.Loader.Loader.ReadCollectionElements(Object[] row, IDataReader resultSet, ISessionImplementor session)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(326,0): at NHibernate.Loader.Loader.GetRowFromResultSet(IDataReader resultSet, ISessionImplementor session, QueryParameters queryParameters, LockMode[] lockModeArray, EntityKey optionalObjectKey, IList hydratedObjects, EntityKey[] keys, Boolean returnProxies)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(453,0): at NHibernate.Loader.Loader.DoQuery(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(236,0): at NHibernate.Loader.Loader.DoQueryAndInitializeNonLazyCollections(ISessionImplementor session, QueryParameters queryParameters, Boolean returnProxies)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(1649,0): at NHibernate.Loader.Loader.DoList(ISessionImplementor session, QueryParameters queryParameters)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(1568,0): at NHibernate.Loader.Loader.ListIgnoreQueryCache(ISessionImplementor session, QueryParameters queryParameters)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Loader.cs(1562,0): at NHibernate.Loader.Loader.List(ISessionImplementor session, QueryParameters queryParameters, ISet`1 querySpaces, IType[] resultTypes)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Loader\Criteria\CriteriaLoader.cs(73,0): at NHibernate.Loader.Criteria.CriteriaLoader.List(ISessionImplementor session)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Impl\SessionImpl.cs(1936,0): at NHibernate.Impl.SessionImpl.List(CriteriaImpl criteria, IList results)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Impl\CriteriaImpl.cs(246,0): at NHibernate.Impl.CriteriaImpl.List(IList results)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Impl\CriteriaImpl.cs(237,0): at NHibernate.Impl.CriteriaImpl.List()
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Impl\CriteriaImpl.cs(398,0): at NHibernate.Impl.CriteriaImpl.UniqueResult()
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Impl\CriteriaImpl.cs(263,0): at NHibernate.Impl.CriteriaImpl.UniqueResult[T]()
D:\proj\CMS3\branches\nh_auth\DomainModel2Tests\Authorization\TempTests.cs(46,0): at CMS.DomainModel.Authorization.TempTests.Test1()
Inner Exception
System.Collections.Generic.KeyNotFoundException
Message: The given key was not present in the dictionary.
Source: mscorlib
StackTrace:
at System.ThrowHelper.ThrowKeyNotFoundException()
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs(2047,0): at NHibernate.Persister.Entity.AbstractEntityPersister.GetAppropriateUniqueKeyLoader(String propertyName, IDictionary`2 enabledFilters)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Persister\Entity\AbstractEntityPersister.cs(2037,0): at NHibernate.Persister.Entity.AbstractEntityPersister.LoadByUniqueKey(String propertyName, Object uniqueKey, ISessionImplementor session)
c:\opt\nhibernate\2.1.2\source\src\NHibernate\Type\EntityType.cs(552,0): at NHibernate.Type.EntityType.LoadByUniqueKey(String entityName, String uniqueKeyPropertyName, Object key, ISessionImplementor session)

I'm using NHibernate 2.1.2 and I've been debugging into the NHibernate source, but I'm coming up empty. Any suggestions? Thanks so much!

© Stack Overflow or respective owner

Related posts about nhibernate

Related posts about nhibernate-mapping