[解決済み】.ToList(), .AsEnumerable(), AsQueryable()の違いは何ですか?
質問
LINQ to EntitiesとLINQ to Objectsの違いについて知っています。
IQueryable
を実装しており、後者は
IEnumerable
で、私の質問範囲はEF 5の中です。
質問ですが、この3つの方法の技術的な違いは何でしょうか?多くの状況で、これら3つの方法はすべて機能することがわかります。また、次のような組み合わせで使用することもあります。
.ToList().AsQueryable()
.
-
その方法とは、具体的にどのようなものなのでしょうか?
-
パフォーマンス上の問題や、どちらかを使用した方が良いというようなことはありますか?
-
なぜ、例えば、1を使うのか。
.ToList().AsQueryable()
の代わりに.AsQueryable()
?
解決方法は?
これについては、いろいろと言いたいことがあります。私が注目するのは
AsEnumerable
と
AsQueryable
と記載し
ToList()
を途中経過で紹介します。
これらのメソッドは何をするのですか?
AsEnumerable
と
AsQueryable
にキャストまたは変換します。
IEnumerable
または
IQueryable
それぞれ と言うと
キャストまたはコンバート
を理由にしています。
-
ソースオブジェクトが既にターゲットインタフェースを実装している場合、ソースオブジェクト自体は返されますが キャスト をターゲットインターフェイスに変換します。言い換えれば、型は変更されないが、コンパイル時の型は変更される。
-
ソースオブジェクトがターゲットインタフェースを実装していない場合、ソースオブジェクトは コンバート をターゲットインターフェイスを実装したオブジェクトに変換します。つまり、型とコンパイル時の型の両方が変更されるわけです。
いくつか例を挙げて説明しましょう。この小さなメソッドは、コンパイル時の型とオブジェクトの実際の型を報告するものです ( 提供:Jon Skeet ):
void ReportTypeProperties<T>(T obj)
{
Console.WriteLine("Compile-time type: {0}", typeof(T).Name);
Console.WriteLine("Actual type: {0}", obj.GetType().Name);
}
任意のlinq-to-sqlを試してみましょう。
Table<T>
を実装している。
IQueryable
:
ReportTypeProperties(context.Observations);
ReportTypeProperties(context.Observations.AsEnumerable());
ReportTypeProperties(context.Observations.AsQueryable());
その結果
Compile-time type: Table`1
Actual type: Table`1
Compile-time type: IEnumerable`1
Actual type: Table`1
Compile-time type: IQueryable`1
Actual type: Table`1
テーブルクラス自体は常に返されますが、その表現は変更されることがわかります。
を実装したオブジェクトは
IEnumerable
ではなく
IQueryable
:
var ints = new[] { 1, 2 };
ReportTypeProperties(ints);
ReportTypeProperties(ints.AsEnumerable());
ReportTypeProperties(ints.AsQueryable());
その結果
Compile-time type: Int32[]
Actual type: Int32[]
Compile-time type: IEnumerable`1
Actual type: Int32[]
Compile-time type: IQueryable`1
Actual type: EnumerableQuery`1
そこにあるのは
AsQueryable()
は、配列を
EnumerableQuery
を表します。
IEnumerable<T>
コレクションを
IQueryable<T>
データソース.quot; (MSDN)。
用途は?
AsEnumerable
は頻繁に使用され、任意の
IQueryable
の実装をLINQ to objects (L2O) に置き換えたもので、前者はL2Oが持つ関数をサポートしていないことが主な理由です。詳しくは
LINQ エンティティに対する AsEnumerable() の効果は何ですか?
.
例えば、Entity Frameworkのクエリでは、限られた数のメソッドしか使用することができません。したがって、例えば、クエリで独自のメソッドを使用する必要がある場合、通常、次のように記述します。
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => MySuperSmartMethod(x))
ToList
- を変換するものです。
IEnumerable<T>
を
List<T>
- は、この目的にもよく使われます。を使うことの利点は
AsEnumerable
vs.
ToList
というのは
AsEnumerable
はクエリを実行しない。
AsEnumerable
は遅延実行を維持し、しばしば役に立たない中間リストを作成しない。
一方、LINQクエリの強制実行が望まれる場合。
ToList
は、そのための方法となり得ます。
AsQueryable
は、列挙可能なコレクションが LINQ ステートメントで式を受け入れるようにするために使用することができます。詳しくはこちらをご覧ください。
コレクションにAsQueryable()を使用する必要がありますか?
.
薬物乱用に注意!
AsEnumerable
は麻薬のように作用します。即効性はありますが、コストがかかり、根本的な問題には対処できません。
スタックオーバーフローの回答で、多くの人が
AsEnumerable
を使用して、LINQ 式のサポートされていないメソッドに関するほぼすべての問題を解決します。しかし、その代償は必ずしも明確ではありません。例えば、こんなことをしたら。
context.MyLongWideTable // A table with many records and columns
.Where(x => x.Type == "type")
.Select(x => new { x.Name, x.CreateDate })
...すべては、次のようなSQL文にきちんと変換されます。
フィルター
(
Where
) と
プロジェクト
(
Select
). つまり、SQL結果セットの長さと幅の両方がそれぞれ縮小されます。
ここで、ユーザーが日付の部分だけを見たい場合は
CreateDate
. Entity Frameworkでは、すぐに次のことがわかります。
.Select(x => new { x.Name, x.CreateDate.Date })
...はサポートされていません(執筆時)。ああ、幸いなことに
AsEnumerable
を修正しました。
context.MyLongWideTable.AsEnumerable()
.Where(x => x.Type == "type")
.Select(x => new { x.Name, x.CreateDate.Date })
確かに、実行されますよ、たぶん。しかし、テーブル全体をメモリに取り込んでから、フィルタとプロジェクションを適用しています。まあ、たいていの人は賢いので
Where
を先に実行します。
context.MyLongWideTable
.Where(x => x.Type == "type").AsEnumerable()
.Select(x => new { x.Name, x.CreateDate.Date })
しかし、それでもすべてのカラムが最初にフェッチされ、プロジェクションはメモリ内で実行されます。
本当の意味での修正は
context.MyLongWideTable
.Where(x => x.Type == "type")
.Select(x => new { x.Name, DbFunctions.TruncateTime(x.CreateDate) })
(でも、それにはもうちょっとだけ知識が必要なんですよね...)。
これらのメソッドでできないことは何ですか?
IQueryableの機能を復元する
さて、重要な注意点があります。を実行するときは
context.Observations.AsEnumerable()
.AsQueryable()
を実行すると、ソースオブジェクトは次のように表現されます。
IQueryable
. (両方のメソッドはキャストするだけで変換しないため)。
しかし、これを実行すると
context.Observations.AsEnumerable().Select(x => x)
.AsQueryable()
その結果、どうなるのでしょうか?
は
Select
を生成します。
WhereSelectEnumerableIterator
. これは、.Net の内部クラスで
IEnumerable
,
ではなく
IQueryable
. つまり、別の型への変換が行われ、その後に続く
AsQueryable
はもう元のソースを返すことはできない。
この意味するところは
AsQueryable
は
は、クエリプロバイダを魔法のように注入する方法ではありません。
を、その特定の機能とともに列挙可能です。例えば、次のようなことをするとします。
var query = context.Observations.Select(o => o.Id)
.AsEnumerable().Select(x => x.ToString())
.AsQueryable()
.Where(...)
where条件は決してSQLに変換されることはありません。
AsEnumerable()
の後に LINQ ステートメントが続くと、エンティティフレームワークのクエリプロバイダとの接続が決定的に切断されます。
この例を意図的に示しているのは、例えば、「インジェクション」しようとする質問をここで見たことがあるからです。
Include
を呼び出して、コレクションに機能を追加します。
AsQueryable
. コンパイルして実行しますが、基礎となるオブジェクトに
Include
の実装はもうない。
実行
両方
AsQueryable
と
AsEnumerable
が実行されない(あるいは
列挙する
) ソースオブジェクトを作成します。その型や表現を変えるだけです。どちらもインターフェイスに関わる
IQueryable
と
IEnumerable
は、起こるのを待っている列挙に過ぎません。これらは、例えば、上記のように
ToList()
.
つまり
IEnumerable
を呼び出して得られた
AsEnumerable
の上に
IQueryable
オブジェクトを実行すると、その下にある
IQueryable
. その後に実行される
IEnumerable
が再び実行されます。
IQueryable
. これは非常に高くつくかもしれません。
具体的な実装方法
ここまでは
Queryable.AsQueryable
と
Enumerable.AsEnumerable
拡張メソッドです。しかし、もちろん、誰でも同じ名前(関数)のインスタンスメソッドや拡張メソッドを書くことができます。
実際、一般的な例として、特定の
AsEnumerable
拡張メソッドは
DataTableExtensions.AsEnumerable
.
DataTable
は実装されていません。
IQueryable
または
IEnumerable
ということで、通常の拡張メソッドは適用されません。
関連
-
[解決済み] コードファーストとモデル・データベースファーストの比較【終了しました
-
[解決済み] EFのマイグレーション。最後に適用したマイグレーションをロールバックしますか?
-
[解決済み] Entity Frameworkで複数行を削除する方法(foreachを使用しない)
-
[解決済み】.ToList(), .AsEnumerable(), AsQueryable()の違いは何ですか?
-
[解決済み] キーワードはサポートされていません。"データソース" Entity Framework Contextの初期化
-
[解決済み] EF Code First "Invalid column name 'Discriminator'" but no inheritance.
-
[解決済み] EF 5 Code First Migrationsから完全なSQLスクリプトを生成する
-
[解決済み] Entity Frameworkのバージョンは?
-
[解決済み] 特定のVSプロジェクトでのみパッケージマネージャーコンソールのマイグレーションを有効にするCommandNotFoundExceptionを発生させる
-
[解決済み] エンティティフレームワークのコードファーストのNULL外部キー
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] 不変量名 'System.Data.SqlClient' を持つ ADO.NET プロバイダに対応する Entity Framework プロバイダが見つかりませんでした。
-
[解決済み] EFのマイグレーション。最後に適用したマイグレーションをロールバックしますか?
-
[解決済み] Entity Framework: "ストアの更新、挿入、または削除ステートメントが予期しない行数 (0) に影響しました。" [クローズド]。
-
[解決済み】IEnumerable vs List - What to Use? どのように動作するのでしょうか?
-
[解決済み】Entity Frameworkで複数のカラムにユニークキー制約を設定する
-
[解決済み] キーワードはサポートされていません。"データソース" Entity Framework Contextの初期化
-
[解決済み] EF Code First "Invalid column name 'Discriminator'" but no inheritance.
-
[解決済み] EF 5 Code First Migrationsから完全なSQLスクリプトを生成する
-
[解決済み] lambdaを使った複数列のグループ化
-
[解決済み] Entity FrameworkとSQL Server View