いくつかのEFデータリポジトリを実装しており、_TOP 1
_を含むクエリがいくつかあります
.Take(1)
の使用を提案する多くの投稿を読みました
レビューしているコードは.First()
を使用しています
これらの両方がオブジェクトの割り当てに対して同じ結果を生成することを理解していますが、実際には両方が同じクエリに解決されますか? DBにクエリを実行すると、実際には両方のリクエストに対して_TOP 1
_が使用されますか?または、列挙型にクエリを完全に実行し、コレクションの最初のエントリを取得しますか?
さらに、.FirstOrDefault()
を使用した場合、異なる動作を期待する必要があるのはなぜですか? IEnumerableを使用する場合、空のコレクションで.First()
を呼び出すとスローされることを知っていますが、このisが実際に_TOP 1
_を含むようにクエリを変更するだけの場合は、 .First()
と.FirstOrDefault()
....の間に機能的な違いはまったくありません。
または、これらのEnumerableエクステンションよりも優れた方法でクエリを実行する_TOP 1
_がありますか?
LINQPad から:
C#:
_age_Centers.Select(c => c.Id).First();
age_Centers.Select(c => c.Id).FirstOrDefault();
age_Centers.Select(c => c.Id).Take(1).Dump();
_
[〜#〜] sql [〜#〜]:
_SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO
SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
GO
SELECT TOP (1) [t0].[Id]
FROM [age_Centers] AS [t0]
_
* Take(1)
はIQueryable
を列挙して返します。
DataContext Log プロパティをテキストファイルのConsole.Outにリダイレクトし、各オプションが生成するクエリを確認します。
**First()** operates on a collection of any number of objects and returns the first object. **Take(1)** operates on a collection of any number of objects and returns a collection containing the first object.
また、Singleを使用することもできますSingle()は、1つのオブジェクトのコレクションを操作し、オブジェクトを単に返します。
.First()
の仕組み:
コレクションがIList型の場合、最初の要素は、コレクションの実装に応じて異なるインデックス位置によってアクセスされます。それ以外の場合、反復子は最初の要素を返します。
そして、.Take(int count)
は常に反復します。
ゲインがある場合、コレクションがIList
を実装し、インデックスによって最初の要素にアクセスする速度がイテレータを返す速度よりも速い場合に発生します。私はそれが重要だとは思わない。 ;)
ソース:
最初にテイク1をクエリするため、クエリに違いはありません。 TakeはIEnumerableを返すため、FirstOrDefaultの呼び出しは1ステップのステートメントになります。とにかくFirstを呼び出す必要があります。
Firstは例外をスローするため、FirstOrDefaultが常に優先されます。
そしてもちろん、EFクエリコンバーターを作成した人は、結果セット全体を実行して最初のアイテムを返す代わりに、テイク1を呼び出すのに十分賢いです。
これは、SQLプロファイラーを使用して確認できます。