编辑 - 在hibernate jira找到完全相同的问题,说明已解决。这仍然是NHibernate的问题
。类别与部门有多对一的关系。 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()
感谢任何帮助。
答案 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