我遇到NHibernate v3.2.0的问题,并且在查询之后:
class DocumentBase {}
class Requisition: DocumentBase {}
class Order: DocumentBase {}
Repository.GetAll<DocumentBase>()
.Where(d => (d is Requisition) && ((Requisition)d).ProductItem != null)
基本查询旨在列出所有文档,但也可以按类型过滤此文档(和准类型,例如没有产品的文档)。在上面的代码中只有一个条件,但谓词可能更复杂,例如:
Repository.GetAll<DocumentBase>()
.Where(d =>
((d is Requisition) && ((Requisition)d).ProductItem != null) ||
(d is Order) ||
[...]
)
执行后,我会收到InvalidPathException
消息Invalid path: 'd.ProductItem'
。
有任何想法吗?是否支持?
到目前为止,我设法通过以下查询绕过了此错误:
Repository.GetAll<DocumentBase>()
.Where(d =>
(d is Requisition) &&
Repository.GetAll<Requisition>()
.Any(r => r.Id == d.Id && r.ProductItem != null)
)
但绝对不是表现最好的选择。
答案 0 :(得分:2)
我猜您的Repository.GetAll<T>
方法正在返回session.Query<T>
。只有有限的表达式子集可以使用Where
子句。 NHibernate尝试将Where表达式转换为HQL,最终转换为SQL。这意味着您不能在Where中编写任何内容并期望它可以工作,而只能在那些存在转换的表达式中编写。但是,NHibernate的Linq提供程序可以是extended。
您的案例可以简化。如果你已经映射了子类...而且你可能会这样做,那么查询可以写成:
Repository.GetAll<Requisition>().Where(r => r.ProductItem != null);
答案 1 :(得分:0)
正如有人提到的,可以在NHibernate中扩展Linq提供程序。这是对我有用的解决方案:
public static class OzirNhExtensions
{
// Cast method to use in query
public static TTarget Cast<TTarget>(this Object source)
{
return ((TTarget)source);
}
}
class CastHqlGeneratorForMethod : BaseHqlGeneratorForMethod
{
public CastHqlGeneratorForMethod()
{
this.SupportedMethods = new MethodInfo[] {
ReflectionHelper.GetMethodDefinition(
() => OzirNhExtensions.Cast<Object>(null)
)
};
}
// In here simply skip cast expression
// (it works probably because I have every sub-entity
// in the same table that base entity)
public override HqlTreeNode BuildHql(
MethodInfo method,
Expression targetObject,
ReadOnlyCollection<Expression> arguments,
HqlTreeBuilder treeBuilder,
IHqlExpressionVisitor visitor)
{
return visitor.Visit(arguments[0]).AsExpression();
}
}
示例查询:
Repository.GetAll<DocumentBase>()
.Where(d => d.Cast<Requisition>().ProductItem != null &&
d.Cast<Requisition>().ProductItem.Name == "Something"
)