NHibernate,通过扩展DefaultLinqToHqlGeneratorsRegistry,使用SQL方法扩展IQueryable

时间:2015-03-18 21:43:27

标签: c# linq nhibernate fluent-nhibernate extension-methods

我使用流畅的NHibernate,我需要随机化查询结果,我想要的是这样的:

select * from table order by newid()

方式,应该是扩展NHibernate IQueryable生成器以使用像QueryableExtension.RandomOrder<T>(this IQueryable<T> list)

这样的方法

通过博客:http://fabiomaulo.blogspot.dk/2010/07/nhibernate-linq-provider-extension.html 而这:Extending LINQ to Nhibernate provider, in combination with Dynamic LINQ problem

我写了这段代码:

public class RandomOrderGenerator : BaseHqlGeneratorForMethod
{
    public RandomOrderGenerator()
    {
        SupportedMethods = new[]
        {
            ReflectionHelper.GetMethod(() => Enumerable.Empty<object>().AsQueryable().RandomOrder()),
            ReflectionHelper.GetMethod(() => Enumerable.Empty<long>().AsQueryable().RandomOrder()),
        };
    }

    public override HqlTreeNode BuildHql(MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
        HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        throw new NotImplementedException();
    }
}

public class MyLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
    public MyLinqToHqlGeneratorsRegistry()
    {
        RegisterGenerator(ReflectionHelper.GetMethod(() => Enumerable.Empty<object>().AsQueryable().RandomOrder()), new RandomOrderGenerator());
    }
}

我已配置使用MyLinqToHqlGeneratorsRegistry,它已创建,我的RandomOrderGenerator已创建,但BuildHql方法永远不会被调用。

使用扩展名:

repository.Query<Table>().Take(10).RandomOrder().Select(x => x.Id);

SupportMethodsRegisterGenerator方法定义应该相同,但为什么我不能让它生成HQL?

1 个答案:

答案 0 :(得分:1)

现在有了解决方案。

我无法使RandomOrder扩展工作,但后来我读到了这个: https://nhibernate.jira.com/browse/NH-3386

这里有LinqExtensionMethod,它会在sql中自动调用该方法。这里的问题是当表达式不依赖于数据库中的任何特定内容时,它会在本地编译,通过这种方式传递特定于该方法的数据库。

repository.Query<Table>().Take(10).OrderBy(x => OrderType.Random(x.Id))...

LinqExtensionMethods由DefaultLinqToHqlGeneratorsRegistry处理,并且还将参数映射到SQL方法,非常简洁,而不是我们想要的。现在sql看起来像这样: select....newid(table.id)

要解决这个问题,我们需要自己映射,以便我们可以忽略参数,所以不要使用Attribute并创建一个hql生成器:

public class RandomOrderHqlGenerator : BaseHqlGeneratorForMethod
{
    private readonly string _name;
    public RandomOrderHqlGenerator()
    {
        _name = "NewId";
    }
    public override HqlTreeNode BuildHql(MethodInfo method, System.Linq.Expressions.Expression targetObject, ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
        HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
    {
        return treeBuilder.MethodCall(_name);
    }
}

RegisterGenerator(ReflectionHelper.GetMethodDefinition(() => OrderType.Random(null)), new RandomOrderHqlGenerator());