System.NullReferenceException when trying to eager load an IDICTIONARY of an association on root entity. Do you see anything wrong with this HQL?

StackOverflow https://stackoverflow.com/questions/21243592

  •  30-09-2022
  •  | 
  •  

Question

EDIT - found exact same issue at hibernate jira which says resolved. Is this still an issue with NHibernate

DB Schema. Category has many-to-one relationship with Department. DepartmentDescription table holds description of a department in multiple languages.

These are entities in C# and their Nhibernate mappings. I have modeled DepartmentDescriptions as an IDictionary on Department

public class Category
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual Department Department { get; set; }
}

public class Department
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual IDictionary<string, string> Description { get; set; }
}

category mapping

<?xml version="1.0" encoding="utf-8" ?>
 <hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NH.Domain"     namespace="NH.Domain">
<class name="Category" table="Category">
<id name="Id" column="Id">
  <generator class="identity"></generator>
</id>
<property name="Name" column="Name"></property>
<many-to-one name="Department" column="DepartmentId" class="Department"></many-to-one>
</class>
</hibernate-mapping>

Department mapping

<?xml version="1.0" encoding="utf-8" ?>
<hibernate-mapping xmlns="urn:nhibernate-mapping-2.2" assembly="NH.Domain" namespace="NH.Domain">
<class name="Department" table="Department">
<id name="Id" column="Id">
  <generator class="identity"></generator>
</id>
<property name="Name" column="Name"></property>
<map name="Description" table="DepartmentDescription">
  <key column="DepartmentId"></key>
  <index column="LanguageCode" type="string"></index>
  <element column="Description" type="string"></element>
</map>
</class>
</hibernate-mapping>

This is the HQL I am using to get a category and eager load its department

select c from Category as c 
join fetch c.Department as dept 
join fetch dept.Description as desc
where c.Id=1

On executing this HQL I get a system.nullreferenceexception - saying object is not set to reference of an object. Here is the stack trace

at NHibernate.Loader.BasicLoader.IsBag(ICollectionPersister collectionPersister)
   at NHibernate.Loader.BasicLoader.PostInstantiate()
   at NHibernate.Hql.Ast.ANTLR.Loader.QueryLoader..ctor(QueryTranslatorImpl queryTranslator, ISessionFactoryImplementor factory, SelectClause selectClause)
   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.DoCompile(IDictionary`2 replacements, Boolean shallow, String collectionRole)
   at NHibernate.Hql.Ast.ANTLR.QueryTranslatorImpl.Compile(IDictionary`2 replacements, Boolean shallow)
   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(IASTNode ast, String queryIdentifier, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
   at NHibernate.Hql.Ast.ANTLR.ASTQueryTranslatorFactory.CreateQueryTranslators(String queryString, String collectionRole, Boolean shallow, IDictionary`2 filters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.HQLStringQueryPlan.CreateTranslators(String hql, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.HQLStringQueryPlan..ctor(String hql, String collectionRole, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.HQLStringQueryPlan..ctor(String hql, Boolean shallow, IDictionary`2 enabledFilters, ISessionFactoryImplementor factory)
   at NHibernate.Engine.Query.QueryPlanCache.GetHQLQueryPlan(String queryString, Boolean shallow, IDictionary`2 enabledFilters)
   at NHibernate.Impl.AbstractSessionImpl.GetHQLQueryPlan(String query, Boolean shallow)
   at NHibernate.Impl.AbstractSessionImpl.CreateQuery(String queryString)
   at NH.Program.Main(String[] args) in Program.cs:line 32
   at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
   at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
   at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
   at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
   at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
   at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
   at System.Threading.ThreadHelper.ThreadStart()

Any help is appreciated.

Was it helpful?

Solution

In this case, I would say, you are doing it correct, but the parser does not read it correctly. Anyhow, what would work is this:

select c from Category as c 
join fetch c.Department as dept 
// join fetch dept.Description as desc
join fetch c.Department.Description as desc // alias not used
where c.Id=1

Such a query would at the end be joining the Department twice..., but with results you'd expect.

The reason, why this bug remains in the HQL parser (in such a mature product as NHibernate is), would have one reason: You are using in some very specific, rare scenario. It is not excuse for NHiberante. But could/should be a sign...

I would suggest, rather then using the IDictinary<ValueType, ValueType>, give it more coding (negative) and create the wrapping object and map it as ILit<MyWrapperObject>. You will gain more standard behavior, and better querying options. Please check Nhibernate query for items that have a Dictionary Property containing value

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top