Note that there are some explanatory texts on larger screens.

plurals
  1. POHow can I eager-load a child collection mapped to a non-primary key in NHibernate 2.1.2?
    text
    copied!<p>I have two objects with a many-to-many relationship between them, as follows:</p> <pre><code>public class LeftHandSide { public LeftHandSide() { Name = String.Empty; Rights = new HashSet&lt;RightHandSide&gt;(); } public int Id { get; set; } public string Name { get; set; } public ICollection&lt;RightHandSide&gt; Rights { get; set; } } public class RightHandSide { public RightHandSide() { OtherProp = String.Empty; Lefts = new HashSet&lt;LeftHandSide&gt;(); } public int Id { get; set; } public string OtherProp { get; set; } public ICollection&lt;LeftHandSide&gt; Lefts { get; set; } } </code></pre> <p>and I'm using a legacy database, so my mappings look like: <strong>Notice that <code>LeftHandSide</code> and <code>RightHandSide</code> are associated by a different column than <code>RightHandSide</code>'s primary key.</strong></p> <pre><code>&lt;class name="LeftHandSide" table="[dbo].[lefts]" lazy="false"&gt; &lt;id name="Id" column="ID" unsaved-value="0"&gt; &lt;generator class="identity" /&gt; &lt;/id&gt; &lt;property name="Name" not-null="true" /&gt; &lt;set name="Rights" table="[dbo].[lefts2rights]"&gt; &lt;key column="leftId" /&gt; &lt;!-- THIS IS THE IMPORTANT BIT: I MUST USE PROPERTY-REF --&gt; &lt;many-to-many class="RightHandSide" column="rightProp" property-ref="OtherProp" /&gt; &lt;/set&gt; &lt;/class&gt; &lt;class name="RightHandSide" table="[dbo].[rights]" lazy="false"&gt; &lt;id name="Id" column="id" unsaved-value="0"&gt; &lt;generator class="identity" /&gt; &lt;/id&gt; &lt;property name="OtherProp" column="otherProp" /&gt; &lt;set name="Lefts" table="[dbo].[lefts2rights]"&gt; &lt;!-- THIS IS THE IMPORTANT BIT: I MUST USE PROPERTY-REF --&gt; &lt;key column="rightProp" property-ref="OtherProp" /&gt; &lt;many-to-many class="LeftHandSide" column="leftId" /&gt; &lt;/set&gt; &lt;/class&gt; </code></pre> <p>The problem comes when I do a query for <code>LeftHandSide</code>'s and eager-load the collection:</p> <pre><code>LeftHandSide lhs = _session.CreateCriteria&lt;LeftHandSide&gt;() .Add(Expression.IdEq(13)) .UniqueResult&lt;LeftHandSide&gt;(); </code></pre> <p>works just fine. But</p> <pre><code>LeftHandSide lhs = _session.CreateCriteria&lt;LeftHandSide&gt;() .Add(Expression.IdEq(13)) .SetFetchMode("Rights", FetchMode.Join) // &lt;-- I really do want to eager-load this collection in this one particular usage scenario. .UniqueResult&lt;LeftHandSide&gt;(); </code></pre> <p>throws an exception (see below). Interestingly,</p> <pre><code>RightHandSide rhs = _session.CreateCriteria&lt;RightHandSide&gt;() .Add(Expression.IdEq(127)) .SetFetchMode("Lefts", FetchMode.Join) // &lt;-- eager-load the other direction .UniqueResult&lt;RightHandSide&gt;(); </code></pre> <p>seems to be perfectly fine as well.</p> <blockquote> <pre><code>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) </code></pre> </blockquote> <p>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!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload