2017-06-09 1 views
-1

LinqのカスタムOrderBy拡張メソッドをエンティティに書き込もうとしています。ここでは、パラメータに基づいてASCまたはDESCをソートできます。Linq to Entities - ラムダステートメントでカスタムメソッド(OrderBy)が失敗する

public static class LinqExtensions 
{ 
    public static IOrderedQueryable<TSource> OrderByExtension<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, bool isDescending = true) 
    { 
     return (isDescending) ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector); 
    } 
} 

これは素晴らしい作品...限り、私はラムダ文の中にこのメソッドを使用していないよう:!私の最初の試みは、以下の通りでした。おもちゃの例は次のようになります。私は上記のコードを実行すると

using (var dbContext = new FooDBEntities()) 
{ 
    var foo = dbContext.Fubars.SelectMany(x => dbContext.Fubars.OrderByExtension(y => y.Foo, true)).ToList(); 
} 

プログラムが吹くと、私は次のエラーを取得する:

Unhandled Exception: System.NotSupportedException: LINQ to Entities does not recognize the method 'System.Linq.IOrderedQueryable`1[ExpressionTreeFoo.Fubar] OrderByExtension[Fubar,String](System.Linq.IQueryable`1[ExpressionTreeFoo.Fubar], System.Linq.Expressions.Expression`1[System.Func`2[ExpressionTreeFoo.Fubar,System.String]], Boolean)' method, and this method cannot be translated into a store expression. 

誤差はかなりそれをすべて言います。フレームワークは、私のカスタム拡張メソッドをSQLが理解できるものに変換する方法を知らない。

私はいくつかの検索を行ってきましたが、これは可能かどうかを明確に示すものは見ていません。だから私の質問は..ラムダ式の内部で動作するカスタムOrderByメソッド(拡張メソッドかどうか)を作る方法はありますか?

+0

あなたはそれが完全に単純なクエリで作業していますか?生成されたSQLをチェックしましたか? –

+0

はい、確認しました。私は使用しています:context.Database.Log = s => System.Diagnostics.Debug.WriteLine(s)は、クエリを印刷します。 – Soto

答えて

-1

真の式ツリーにコンパイルすることができません:LinqKit.EntityFramework

それが動作する方法は、あなたモミです.AsExpandable()これは、IQueryableの周りにラッパーを配置します。次に、インラムダ式の.Invokeを呼び出す必要があります。 InvokeはLinqKitの拡張メソッドです。このクエリが呼び出されると、LinqKitは式ツリーを再帰的にスキャンし、拡張子Invokeを呼び出す式にヒットすると、Invokeへの呼び出しを削除し、CLRエンジンが理解できる方法で式ツリーを書き換えます。完全な説明はで見つけることができます:http://www.albahari.com/nutshell/linqkit.aspx

static void EFTest() 
{ 
    using (var dbContext = new DBEntities()) 
    { 
     // debug - print query 
     dbContext.Database.Log = Console.WriteLine; 

     // get order by expression 
     var orderByExpression = GetOrderByExpression(dbContext, true); 

     // execute query 
     var result = dbContext.FooTables 
           .AsExpandable() 
           .SelectMany(x => orderByExpression.Invoke(x)) 
           .ToList(); 
    } 
} 
private static Expression<Func<FooTable, IOrderedQueryable<FooTable>>> GetOrderByExpression(DBEntities dbContext, bool isDesending) 
{ 
    if (isDesending) 
    { 
     return x => dbContext.FooTables.OrderByDescending(y => y.Date); 
    } 
    else 
    { 
     return x => dbContext.FooTables.OrderBy(y => y.Date); 
    } 
} 
2

これは、ラムダがSQLとの既知のインタフェースを直接持つコンパイルされた式ツリーではないためです。あなたが作成している意味でのラムダは、匿名のC#メソッドです。このメソッドは、CLRによってのみ実行可能です。それらは同じ構文を共有しますが、フレームワークの異なる要素です。独自のカスタムLinq-To-Entities式を実装したい場合は、建物Expression Treesを調べる必要があります。この中へ

(isDescending) ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector); 

: -

単にそれを説明するにはどのようにあなたはこれをオンにしますか?

SELECT * FROM [MyTable] ORDER BY [MyTable].[MyColumn] DESC 

Linqの式ツリーを使用してこれを行う方法を正しく定義する必要があります。

Hereはあなた次第(ただし、解答なし) Hereに類似の質問はあなたが渡しているものので、あなたがラムダ式にそれを渡した場合にのみ、それが失敗した

理由がある式ツリー上のMicrosoftのマニュアルであります私は最終的にNuGetパッケージを使用して解決策を見つけた

+1

ラムダステートメントのニュアンスへの迅速な対応と洞察をいただき、ありがとうございます。あなたが提供したリンクをチェックします。 -cheers – Soto

+0

@Sotoこれがあなたのニーズに合っている場合は、答えとしてマークすることを検討してください。 –

+0

Expression Tressを構築するための独自のフレームワークを作成するには、まだ解決策がありません。私はあなたのリンクを使って解決策を考案しても、それ以外の解決策がわかっていれば解決策を見つけることができます。 – Soto