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を使用して同様のクエリを作成できますか?どうやらそうではありません。標準のHQLAddHours関数はありません。したがって、この新しい関数を登録する必要があります。NHibernateは方言を使用して、hqlとベンダー固有のSQL構文を変換します。これを行うには、既存の方言クラスから派生した新しい方言クラスを作成し、RegisterFunctionsメソッドをオーバーライドする必要があります。しかし、これは問題の前半だけを解決します。次に、LINQでこの関数を使用する方法をNHibernateに示す必要があります。DateTime.AddHours(double hours)メソッドと以前に登録されたカスタムhql関数の間で「マップ」する必要があります。NHibernateはこの目的でレジストリを使用します。デフォルトのlinq-to-hqlレジストリを拡張する必要があります。

NHibernate3.3で動作した例を示します

新しい方言クラスを作成します(私の例では、事前定義されたMsSql2008Dialectを使用します)

    パブリッククラスEnhancedMsSql2008Dialect:MsSql2008Dialect
    {{
        保護されたオーバーライドvoidRegisterFunctions(){
            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
    {{
        public DateTimeMethodsHqlGenerator(){
            SupportedMethods = new [] {
                ReflectionHelper.GetMethodDefinition((DateTime x)=> x.AddHours(1))
            };
        }

        パブリックオーバーライドHqlTreeNodeBuildHql(System.Reflection.MethodInfoメソッド、System.Linq.Expressions.Expression targetObject、System.Collections.ObjectModel.ReadOnlyCollection引数、HqlTreeBuilder treeBuilder、NHibernate.Linq.Visitors.IHqlExpressionVisitorビジター){
            treeBuilder.MethodCall( "add_hours"、visitor.Visit(arguments [0])。AsExpression()、visitor.Visit(targetObject).AsExpression());を返します。
        }
    }

デフォルトのLINQ-to-HQLレジストリクラスを拡張します

    パブリッククラスEnhancedLinqToHqlGeneratorsRegistry:DefaultLinqToHqlGeneratorsRegistry
    {{
        public 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>();

次の3つのクラスを追加します。-

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 に答える