0

我遇到了 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) ||
        [...]
    )

执行时,我收到InvalidPathExceptionmessage Invalid path: 'd.ProductItem'。有任何想法吗?是否支持?

到目前为止,我设法通过以下查询绕过了这个错误:

Repository.GetAll<DocumentBase>()
    .Where(d => 
        (d is Requisition) &&
        Repository.GetAll<Requisition>()
            .Any(r => r.Id == d.Id && r.ProductItem != null)
    )

但就性能而言,它绝对不是最佳选择。

4

2 回答 2

2

我猜你的Repository.GetAll<T>方法正在返回session.Query<T>。只有有限的表达式子集可以包含您的Where子句。NHibernate 尝试将您的 Where 表达式转换为 HQL,并最终转换为 SQL。这意味着您不能在 Where 中编写任何内容并期望它能够工作,而只能是那些存在转换的表达式。但是,NHibernate 的 Linq 提供程序可以扩展

您的情况可以简化。如果你有你的子类映射......你可能这样做,查询可以写成:

Repository.GetAll<Requisition>().Where(r => r.ProductItem != null);
于 2012-08-08T08:47:33.980 回答
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"
    )
于 2012-09-13T21:18:18.833 回答