NHibernate,通过扩展 DefaultLinqToHqlGeneratorsRegistry 使用 SQL 方法扩展 IQueryable
NHibernate, extend IQueryable with SQL method by extending DefaultLinqToHqlGeneratorsRegistry
我使用流畅的 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);
SupportMethods
和RegisterGenerator
的方法定义应该是一样的,但是为什么我获取不到生成HQL?
现在有了解决方案。
我无法使 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());
我使用流畅的 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);
SupportMethods
和RegisterGenerator
的方法定义应该是一样的,但是为什么我获取不到生成HQL?
现在有了解决方案。
我无法使 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());