NHibernate + IQueryable访问子类型属性在哪里

时间:2012-08-08 08:32:14

标签: c# .net linq nhibernate iqueryable

我遇到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)
    )

但绝对不是表现最好的选择。

2 个答案:

答案 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"
    )