web-dev-qa-db-ja.com

LINQ to SQL .AsEnumerable()を誤解していますか?

このコードを検討してください:

_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を使用してクエリを実行し、次にCountSum、およびAverageにLINQ-to-Objectsを使用すると思いました。代わりに、LINQPadでこれを行うと、同じクエリが3回実行されていることがわかります。 .AsEnumerable().ToList()に置き換えると、クエリは1回だけ行われます。

AsEnumerableが何であるか/何をするかについて何かが足りませんか?

49
Ocelot20

_AsEnumerable(_)を呼び出してもクエリは実行されず、列挙されます。

IQueryableは、_LINQ to SQL_がその魔法を実行できるようにするインターフェースです。 IQueryableIEnumerableを実装しているため、AsEnumerable()を呼び出すと、そこから呼び出される拡張メソッド、つまりIQueryableメソッドからに変更されます。 IEnumerable-メソッド(つまり、この特定のケースでは_LINQ to SQL_から_LINQ to Objects_に変更します)。しかし、あなたはnot実際のクエリを実行しているだけで、how全体が実行されることになります。

クエリを強制的に実行するには、ToList()を呼び出す必要があります。

58
Justin Niessner

はい。 AsEnumerableが行うことは、CountSum、およびAverage関数をクライアント側で実行させることだけです(つまり、元に戻します)結果セット全体がクライアントに送信されると、クライアントは、SQLでCOUNT()SUM()およびAVG()ステートメントを作成する代わりに、これらの集計を実行します。

14
Adam Robinson

さて、あなたは正しい軌道に乗っています。問題は、IQueryableAsEnumerable呼び出しの前のステートメント)もIEnumerableであるため、呼び出しは事実上nopであるということです。クエリを強制するには、特定のメモリ内データ構造(ToList()など)に強制する必要があります。

4
James Curran

ジャスティンニースナーの答え 完璧です。

ここで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を返す

3
Lijo

ToListは、Linqにデータベースからレコードをフェッチするように強制すると思います。次に、続行する計算を実行すると、データベースを使用するのではなく、メモリ内のオブジェクトに対して実行されます。

戻り値の型をEnumerableのままにしておくと、計算を実行するコードによって呼び出されるまでデータがフェッチされないことを意味します。これのノックオンは、データベースが3回ヒットすることだと思います-計算ごとに1回で、データはメモリに保持されません。

1
Sergio