这是写这样的东西的方法:
public class Item
{
public DateTime Start { get; set; }
public DateTime Finish{ get; set; }
}
Sessin.Query<Item>.Where( x => x.Start.AddHours( 3 ) > x.Finish );
现在我得到了一个例外
[NotSupportedException:System.DateTime AddHours(Double)]
答案 0 :(得分:7)
没有简单的方法可以让你的LINQ查询工作。您的方案存在的问题是NHibernate不知道如何翻译DateTime.AddHours(double hours)
方法。但是你可以使用HQL编写类似的查询吗?显然不是。没有标准的HQL AddHours函数。因此,您必须注册此新功能。 NHibernate使用方言在hql和特定于供应商的SQL语法之间进行转换。为了做到这一点,你必须创建一个新的方言类,派生自一个expend类并覆盖RegisterFunctions方法。
但这只解决了问题的前半部分。接下来,你必须向NHibernate展示如何在LINQ中使用这个函数。您必须在DateTime.AddHours(double hours)
方法和先前注册的自定义hql函数之间“映射”。 NHibernate为此目的使用注册表。您将不得不扩展默认的linq-to-hql注册表。
我将展示一个适用于NHibernate 3.3的示例
创建一个新的方言类(我的示例使用预定义的MsSql2008Dialect)
public class EnhancedMsSql2008Dialect : MsSql2008Dialect { protected override void RegisterFunctions() { base.RegisterFunctions(); RegisterFunction("add_hours", new SQLFunctionTemplate(NHibernateUtil.DateTime, "dateadd(hour, ?1, ?2)")); } }
创建一个新的LINQ-to-HQL生成器类,它知道如何翻译AddHours方法
using NHibernate.Linq.Functions; using NHibernate.Linq; using NHibernate.Hql.Ast; public class DateTimeMethodsHqlGenerator : BaseHqlGeneratorForMethod { public DateTimeMethodsHqlGenerator() { SupportedMethods = new[] { ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1)) }; } public override HqlTreeNode BuildHql(System.Reflection.MethodInfo method, System.Linq.Expressions.Expression targetObject, System.Collections.ObjectModel.ReadOnlyCollection arguments, HqlTreeBuilder treeBuilder, NHibernate.Linq.Visitors.IHqlExpressionVisitor visitor) { return treeBuilder.MethodCall("add_hours", visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(targetObject).AsExpression()); } }
扩展默认的LINQ-to-HQL注册表类
public class EnhancedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry { public EnhancedLinqToHqlGeneratorsRegistry() : base() { // RegisterGenerator(ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1)), new DateTimeMethodsHqlGenerator()); } }
配置
cfg.DataBaseIntegration(c => { c.Dialect<EnhancedMsSql2008Dialect>(); }); cfg.LinqToHqlGeneratorsRegistry<EnhancedLinqToHqlGeneratorsRegistry>();
答案 1 :(得分:5)
如果你正在使用NH 3.3和Loquacious配置,那么你可以做这样的事情......
将LinqToHqlGeneratorsRegistry
添加到配置中: -
var configure = new Configuration()
.DataBaseIntegration(x => {
x.Dialect<CustomDialect>();
x.ConnectionStringName = "db";
})
.LinqToHqlGeneratorsRegistry<MyLinqtoHqlGeneratorsRegistry()
.CurrentSessionContext<WebSessionContext>();
并添加以下三个类: -
public class MyLinqtoHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
{
public MyLinqtoHqlGeneratorsRegistry()
{
this.Merge(new AddHoursGenerator());
}
}
public class AddHoursGenerator : BaseHqlGeneratorForMethod
{
public AddHoursGenerator()
{
SupportedMethods = new[] {
ReflectionHelper.GetMethodDefinition<DateTime?>(d =>
d.Value.AddHours((double)0))
};
}
public override HqlTreeNode BuildHql(MethodInfo method,
System.Linq.Expressions.Expression targetObject,
ReadOnlyCollection<System.Linq.Expressions.Expression> arguments,
HqlTreeBuilder treeBuilder, IHqlExpressionVisitor visitor)
{
return treeBuilder.MethodCall("AddHours",
visitor.Visit(targetObject).AsExpression(),
visitor.Visit(arguments[0]).AsExpression()
);
}
}
public class CustomDialect : MsSql2008Dialect
{
public CustomDialect()
{
RegisterFunction(
"AddHours",
new SQLFunctionTemplate(
NHibernateUtil.DateTime,
"dateadd(hh,?2,?1)"
)
);
}
}
我的基础是blog post由fabio。
您现在可以按原样使用您的代码: -
Session.Query<Item>.Where( x => x.Start.AddHours( 3 ) > x.Finish );
这在3.2中也是可能的,但public override HqlTreeNode BuildHql(..)
参数略有不同......