このコードを検討してください:
_var query = db.Table
.Where(t => SomeCondition(t))
.AsEnumerable();
int recordCount = query.Count();
int totalSomeNumber = query.Sum();
decimal average = query.Average();
_
query
の実行に非常に長い時間がかかると想定します。レコード数、返された合計SomeNumber
を取得し、最後に平均を取る必要があります。私の読書に基づいて、.AsEnumerable()
はLINQ-to-SQLを使用してクエリを実行し、次にCount
、Sum
、およびAverage
にLINQ-to-Objectsを使用すると思いました。代わりに、LINQPadでこれを行うと、同じクエリが3回実行されていることがわかります。 .AsEnumerable()
を.ToList()
に置き換えると、クエリは1回だけ行われます。
AsEnumerable
が何であるか/何をするかについて何かが足りませんか?
_AsEnumerable(
_)を呼び出してもクエリは実行されず、列挙されます。
IQueryable
は、_LINQ to SQL
_がその魔法を実行できるようにするインターフェースです。 IQueryable
はIEnumerable
を実装しているため、AsEnumerable()
を呼び出すと、そこから呼び出される拡張メソッド、つまりIQueryable
メソッドからに変更されます。 IEnumerable
-メソッド(つまり、この特定のケースでは_LINQ to SQL
_から_LINQ to Objects
_に変更します)。しかし、あなたはnot実際のクエリを実行しているだけで、how全体が実行されることになります。
クエリを強制的に実行するには、ToList()
を呼び出す必要があります。
はい。 AsEnumerable
が行うことは、Count
、Sum
、およびAverage
関数をクライアント側で実行させることだけです(つまり、元に戻します)結果セット全体がクライアントに送信されると、クライアントは、SQLでCOUNT()
SUM()
およびAVG()
ステートメントを作成する代わりに、これらの集計を実行します。
さて、あなたは正しい軌道に乗っています。問題は、IQueryable
(AsEnumerable
呼び出しの前のステートメント)もIEnumerable
であるため、呼び出しは事実上nopであるということです。クエリを強制するには、特定のメモリ内データ構造(ToList()
など)に強制する必要があります。
ジャスティンニースナーの答え 完璧です。
ここでMSDNの説明を引用したいだけです: 。NET言語-リレーショナルデータの統合クエリ
AsEnumerable()演算子は、ToList()やToArray()とは異なり、クエリを実行しません。それはまだ延期されています。 AsEnumerable()演算子は、クエリの静的型付けを変更するだけで、IQueryableをIEnumerableに変換し、コンパイラをだましてクエリの残りの部分をローカルで実行されたものとして処理します。
私はこれが意味するものであることを願っています:
IQueryable-methodsからIEnumerable-methodsへ(つまり、LINQからSQL、LINQ、Objectsへの変更)
オブジェクトへのLINQになったら、オブジェクトのメソッドを適用できます(例: ToString() )。これは、LINQに関するよくある質問の1つについての説明です- LINQ toEntitiesがメソッド 'System.String ToString()を認識しないのはなぜですか?
ASENUMERABLE --codeblog.jonskeet によると、AsEnumerable
は次の場合に便利です。
データベース内のクエリのいくつかの側面、そして.NETでのもう少しの操作-特に、LINQ to SQL(または使用しているプロバイダー)で基本的に実装できない側面がある場合。
それはまた言う:
私たちが行っているのは、クエリを介して伝播するシーケンスのコンパイル時の型をIQueryableからIEnumerableに変更することだけです。ただし、コンパイラは代わりにEnumerableのメソッドを使用します(デリゲートを取得し、LINQ to Objectsで実行します)。 Queryableにあるものの1つ(式ツリーを取得し、通常はアウトプロセスで実行します)。
最後に、この関連する質問も参照してください。 IEnumerableとIQueryableを返す
ToListは、Linqにデータベースからレコードをフェッチするように強制すると思います。次に、続行する計算を実行すると、データベースを使用するのではなく、メモリ内のオブジェクトに対して実行されます。
戻り値の型をEnumerableのままにしておくと、計算を実行するコードによって呼び出されるまでデータがフェッチされないことを意味します。これのノックオンは、データベースが3回ヒットすることだと思います-計算ごとに1回で、データはメモリに保持されません。