5

是在哪里写这样的东西:

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)]

4

2 回答 2

7

没有简单的方法可以使您的 LINQ 查询正常工作。您的方案的问题是 NHibernate 不知道如何翻译DateTime.AddHours(double hours)方法。但是你能用 HQL 写一个类似的查询吗?显然不是。没有标准的 HQL AddHours 函数。因此,您必须注册此新功能。NHibernate 使用方言在 hql 和特定于供应商的 SQL 语法之间进行转换。为此,您必须创建一个派生自现有方言类的新方言类并覆盖 RegisterFunctions 方法。但这仅解决了问题的前半部分。接下来你必须向 NHibernate 展示如何在 LINQ 中使用这个函数。DateTime.AddHours(double hours)您必须在方法和先前注册的自定义 hql 函数之间“映射” 。NHibernate 为此目的使用了一个注册表。您将不得不扩展默认的 linq-to-hql 注册表。

我将展示一个使用 NHibernate 3.3 的示例

创建一个新的方言类(我的示例使用预定义的 MsSql2008Dialect)

    公共类 EnhancedMsSql2008Dialect : MsSql2008Dialect
    {
        受保护的覆盖无效 RegisterFunctions() {
            base.RegisterFunctions();
            RegisterFunction("add_hours", new SQLFunctionTemplate(NHibernateUtil.DateTime, "dateadd(hour, ?1, ?2)"));
        }
    }

创建一个知道如何翻译 AddHours 方法的新 LINQ-to-HQL 生成器类

    使用 NHibernate.Linq.Functions;
    使用 NHibernate.Linq;
    使用 NHibernate.Hql.Ast;

    公共类 DateTimeMethodsHqlGenerator : BaseHqlGeneratorForMethod
    {
        公共 DateTimeMethodsHqlGenerator() {
            SupportedMethods = new[] {
                ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1))
            };
        }

        公共覆盖 HqlTreeNode BuildHql(System.Reflection.MethodInfo 方法,System.Linq.Expressions.Expression targetObject,System.Collections.ObjectModel.ReadOnlyCollection 参数,HqlTreeBuilder treeBuilder,NHibernate.Linq.Visitors.IHqlExpressionVisitor 访问者){
            return treeBuilder.MethodCall("add_hours", visitor.Visit(arguments[0]).AsExpression(), visitor.Visit(targetObject).AsExpression());
        }
    }

扩展默认的 LINQ-to-HQL 注册表类

    公共类 EnhancedLinqToHqlGeneratorsRegistry : DefaultLinqToHqlGeneratorsRegistry
    {
        公共 EnhancedLinqToHqlGeneratorsRegistry() : base() {
            //
            RegisterGenerator(ReflectionHelper.GetMethodDefinition((DateTime x) => x.AddHours(1)), new DateTimeMethodsHqlGenerator());
        }
    }

配置

    cfg.DataBaseIntegration(c => {
        c.Dialect<EnhancedMsSql2008Dialect>();
    });
    cfg.LinqToHqlGeneratorsRegistry<EnhancedLinqToHqlGeneratorsRegistry>();
于 2012-05-15T20:39:35.453 回答
6

如果您使用的是 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)"
                  )
             );
    }
}

我是根据fabio的这篇博文得出的。

您现在可以按原样使用您的代码:-

Session.Query<Item>.Where( x => x.Start.AddHours( 3 ) > x.Finish );

这在 3.2 中也是可能的,但public override HqlTreeNode BuildHql(..)参数略有不同......

于 2012-05-15T20:33:57.750 回答