使用自定义 hql 生成器将 linq-to-nhibernate 扩展

本文关键字:linq-to-nhibernate 扩展 自定义 hql | 更新日期: 2023-09-27 17:56:39

目标是使用 NHibernate 和 Linq 做这样的事情:

Session.Query<MyClass>().Where(x => x.DateGreaterThen(DateTime.Now))

这个例子有点简化,但想法是,在 Where 谓词中,我想调用 MyClass 方法。所以MyClass看起来像:

public class MyClass
{
    public static readonly Expression<Func<MyClass, DateTime, bool>> GreaterThenExpression =
        (x, dt) => x.MyDateTimeProperty > dt.Date;
    private static readonly Func<MyClass, DateTime, bool> GreaterThenFunc = GreaterThenExpression.Compile();
    public Guid Id { get; set; }
    public DateTime MyDateTimeProperty { get; set; }
    public bool DateGreaterThen(DateTime dt)
    {
        return GreaterThenFunc(this, dt);
    }
}

自定义生成器:

public class EntityMethodGenerator<T1, T2, TResult> : BaseHqlGeneratorForMethod
{
    private Expression<Func<T1, T2, TResult>>  _returnValueExpression;
    public EntityMethodGenerator()
    {
        SupportedMethods = new[]
                               {
                                   ReflectionHelper.GetMethodDefinition<MyClass>(myClass => myClass.DateGreaterThen(DateTime.Now))
                               };
    }
    public static void Register(ILinqToHqlGeneratorsRegistry registry, Expression<Action<T1>> method, Expression<Func<T1, T2, TResult>> returnValueExpression)
    {
        var generator = new EntityMethodGenerator<T1, T2, TResult> { _returnValueExpression = returnValueExpression };
        registry.RegisterGenerator(ReflectionHelper.GetMethodDefinition(method), generator);
    }
    public override HqlTreeNode BuildHql(
        MethodInfo method,
        Expression targetObject,
        ReadOnlyCollection<Expression> arguments,
        HqlTreeBuilder treeBuilder,
        IHqlExpressionVisitor visitor)
    {
        return visitor.Visit(_returnValueExpression);
    }
}

最后是自定义生成器注册表:

public class OwnLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public OwnLinqToHqlGeneratorsRegistry()
    {
        EntityMethodGenerator<MyClass, DateTime, bool>.Register(this, (myClass) => myClass.DateGreaterThen(DateTime.Now), MyClass.GreaterThenExpression);
    }   
}

但是这不起作用,我System.Data.SqlClient.SqlException : Invalid column name 'dt'.怀疑我的 BuildHql 方法没有正确实现,有什么帮助解决这个问题吗?

顺便说一下,我想在生成器中使用表达式,就像我的GreaterThenExpression一样,而不是BuildHql方法中手动构建 HqlTree

使用自定义 hql 生成器将 linq-to-nhibernate 扩展

GreaterThenExpression 是一个 lamba。在 BuildHql() 中,您还需要注意目标对象和参数,否则您只是在 HQL 树中插入一些未应用的 lambda 的 HQL 转换。

您需要提取 lambda 的主体并将其参数替换为目标对象和参数。然后你可以从中生成 HQL。尝试使用 Remotion.Linq.Parsing.ExpressionTreeVisiters.MultiReplacingExpressionTreeVisitor。

(附带说明一下,它应该是大于,而不是大于。