尝试在根实体上急切加载关联的IDICTIONARY时System.NullReferenceException。你觉得这个HQL有什么问题吗?

时间:2014-01-20 20:32:47

标签: nhibernate hql

编辑 - 在hibernate jira找到完全相同的问题,说明已解决。这仍然是NHibernate的问题

DB Schema。类别与部门有多对一的关系。 DepartmentDescription表包含多种语言的部门描述。

这些是C#中的实体及其Nhibernate映射。我已将DepartmentDescriptions建模为部门的IDictionary

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; }
}

类别映射

<?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>

部门映射

<?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>

这是我用来获取类别并急切加载其部门的HQL

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

在执行这个HQL时,我得到一个system.nullreferenceexception - 说对象没有设置为对象的引用。这是堆栈跟踪

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()

感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

在这种情况下,我会说,你做得对,但是解析器没有正确读取它。无论如何,这将是有用的:

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

这样的查询最终会加入Department两次......,但会得到您期望的结果。

原因,为什么这个bug仍然存在于HQL解析器中(在像NHibernate这样的成熟产品中),原因有一个:你正在使用一些非常特殊的罕见场景。这不是NHiberante的借口。但是可能/应该是一个标志......

我建议,而不是使用IDictinary<ValueType, ValueType>,给它更多编码(否定)并创建包装对象并将其映射为ILit<MyWrapperObject>。您将获得更多标准行为和更好的查询选项。请检查Nhibernate query for items that have a Dictionary Property containing value