回答:
他の人があなたがどちらか一方を使用する理由を書いたことを知っていますが、もう一方を意味するとき、なぜあなたがどちらかを使用すべきでないかを説明したいと思いました。
注:私のコードでは通常使用FirstOrDefault()
しますSingleOrDefault()
が、それは別の質問です。
たとえば、Customers
複合キー(ID
、Lang
)を使用してさまざまな言語で格納するテーブルを考えます。
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).First();
上のこのコードは、起こり得る論理エラーを引き起こします(追跡が困難です)。複数のレコードが返されます(顧客レコードが複数の言語であると仮定した場合)。ただし、常に最初のレコードのみが返されます。それは予測不可能です。
あなたの意図はシングルCustomer
ユースを返すことなのでSingle()
;
以下は例外をスローします(この場合はこれが必要です)。
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 ).Single();
次に、額に自分をぶつけて、自分に言います。おっと!言語フィールドを忘れてしまった!以下は正しいバージョンです。
DBContext db = new DBContext();
Customer customer = db.Customers.Where( c=> c.ID == 5 && c.Lang == "en" ).Single();
First()
次のシナリオで役立ちます。
DBContext db = new DBContext();
NewsItem newsitem = db.NewsItems.OrderByDescending( n => n.AddedDate ).First();
これは1つのオブジェクトを返し、並べ替えを使用しているため、返されるのは最新のレコードになります。
Single()
常に明示的に常に1レコードを返す必要があると思われる場合に使用すると、論理エラーを回避するのに役立ちます。
customers.Where(predicate).Single()
customers.Single(predicate)
ますか?
Singleは、基準に一致するレコードが複数見つかった場合に例外をスローします。最初は常にリストから最初のレコードを選択します。クエリが1つのレコードのみを返す場合は、を使用できますFirst()
。
InvalidOperationException
コレクションが空の場合、どちらも例外をスローします。または、を使用できますSingleOrDefault()
。リストが空の場合、これは例外をスローしません
シングル()
クエリの単一の特定の要素を返します
使用時:要素が1つだけ必要な場合。0または1以下。リストが空の場合、または複数の要素がある場合は、「シーケンスに複数の要素が含まれています」という例外がスローされます。
SingleOrDefault()
クエリの単一の特定の要素、または結果が見つからない場合はデフォルト値を返します
使用時:0または1要素が必要な場合。リストに2つ以上のアイテムがある場合、例外がスローされます。
最初()
複数の結果を持つクエリの最初の要素を返します。
使用時:1つ以上の要素が期待され、最初の要素のみが必要な場合。リストに要素が含まれていない場合は、例外がスローされます。
FirstOrDefault()
任意の量の要素を含むリストの最初の要素、またはリストが空の場合はデフォルト値を返します。
使用時:複数の要素が予想され、最初の要素のみが必要な場合。または、リストが空で、指定したタイプのデフォルト値をと同じにする必要があります
default(MyObjectType)
。例:リストのタイプがリストlist<int>
の最初の数値を返す場合、またはリストが空の場合は0を返します。の場合list<string>
、リストの最初の文字列を返します。リストが空の場合はnullを返します。
First
場合に、1つ以上の要素が期待される場合にのみ使用できるように変更しますFirstOrDefault
。
これらの2つの方法には微妙な意味上の違いがあります。
Single
1つ以上の要素を含まないシーケンスから最初の(そして唯一の)要素を取得するために使用します。シーケンスに複数の要素Single
がある場合は、要素が1つだけであることを示しているため、を呼び出すと例外がスローされます。
First
任意の数の要素を含むことができるシーケンスから最初の要素を取得するために使用します。シーケンスに複数の要素がある場合、シーケンスFirst
の最初の要素のみが必要であり、それ以上存在してもかまわないことを示しているため、呼び出しによって例外がスローされることはありません。
シーケンスに要素が含まれていない場合、両方のメソッドが少なくとも1つの要素の存在を期待しているため、両方のメソッド呼び出しで例外がスローされます。
複数のアイテムがある場合に例外がスローされるようにしたくない場合は、を使用しますFirst()
。
どちらも効率的です。最初の項目を取ってください。 First()
2番目のアイテムがあるかどうかを確認する必要がないので、少し効率的です。
唯一の違いはSingle()
、列挙には最初から1つの項目しかないと想定されているため、複数ある場合は例外がスローされます。あなたは使い .Single()
ますが、具体的に例外がスローされたい場合は、このケースでは。
私が思い出すと、Single()は最初の要素の後に別の要素があるかどうかをチェックし(そうである場合は例外をスローします)、First()はそれを取得した後に停止します。シーケンスが空の場合、どちらも例外をスローします。
個人的には、常にFirst()を使用します。
パフォーマンスについて:同僚と私はSingle vs First(またはSingleOrDefault vs FirstOrDefault)のパフォーマンスについて話し合っており、First(またはFirstOrDefault)の方が高速でパフォーマンスが向上するという点を主張していました(私はすべてアプリを作成することです)より速く実行する)。
これについて議論するStack Overflowの投稿をいくつか読んだことがあります。SingleではなくFirstを使用するとパフォーマンスが少し向上すると言う人もいます。これは、Firstが単に最初のアイテムを返す一方で、Singleがすべての結果をスキャンして重複がないことを確認する必要があるためです(つまり、テーブルの最初の行にアイテムが見つかった場合でも、1行おきにスキャンしてエラーをスローする条件に一致する2番目の値がないことを確認してください)。「ファースト」の方が「シングル」よりも速いという確固たる地位にいるように感じたので、それを証明し、議論を休止しました。
データベースにテストをセットアップし、1,000,000行のID UniqueIdentifier Foreign UniqueIdentifier Info nvarchar(50)を追加しました(「0」から「999,9999」までの数字の文字列が入力されています)
データを読み込み、IDを主キーフィールドとして設定しました。
LinqPadを使用して、私の目標は、Singleを使用して「Foreign」または「Info」の値を検索した場合、Firstを使用するよりもはるかに悪いことを示すことでした。
私が得た結果を説明することはできません。ほとんどすべての場合で、SingleまたはSingleOrDefaultを使用した方がわずかに高速でした。これは論理的には意味がありませんが、共有したかったのです。
例:私は次のクエリを使用しました:
var q = TestTables.First(x=>x.Info == "314638") ;
//Vs.
Var q = TestTables.Single(x=>x.Info =="314638") ; //(this was slightly faster to my surprise)
Firstの方が速いことを証明するインデックス付きの考えではない 'Foreign'キーフィールドで同様のクエリを試してみましたが、私のテストではSingleは常にわずかに高速でした。
あなたは違いを得るために簡単な例を試すことができます。3行目で例外がスローされます。
List<int> records = new List<int>{1,1,3,4,5,6};
var record = records.First(x => x == 1);
record = records.Single(x => x == 1);
従業員エンティティのレコード:
Employeeid = 1
:このIDを持つ従業員は1人のみ
Firstname = Robert
:この名前の複数の従業員
Employeeid = 10
:このIDの従業員はいません
今では何を理解することが必要だSingle()
とFirst()
詳細に意味します。
シングル()
Single()は、テーブルに一意に存在する単一のレコードを返すために使用されます。したがって、以下のクエリemployeed =1
は、1であるEmployeeが1つしかないため、Employeeを返しますEmployeed
。2つのレコードがある場合EmployeeId = 1
、エラーがスローされます(の例を使用している2番目のクエリの以下のエラーFirstname
。
Employee.Single(e => e.Employeeid == 1)
上記は1つのレコードを返します。 employeeId
Employee.Single(e => e.Firstname == "Robert")
のテーブルに複数のレコードがあるため、上記では例外がスローされFirstName='Robert'
ます。例外は
InvalidOperationException:シーケンスに複数の要素が含まれています
Employee.Single(e => e.Employeeid == 10)
これも、id = 10のレコードが存在しないため、例外をスローします。例外は
InvalidOperationException:シーケンスに要素が含まれていません。
以下の場合EmployeeId = 10
は、nullを返しますが、私たちが使用しているとしてSingle()
、それはエラーがスローされます。nullエラーを処理するには、を使用する必要がありますSingleOrDefault()
。
最初()
First()は、複数のレコードから対応するレコードを昇順で並べ替えてbirthdate
返すため、最も古い 'Robert'が返されます。
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Firstname == "Robert")
上記は、DOBに従って、最も古いもの、Robertを返す必要があります。
Employee.OrderBy(e => e. Birthdate)
.First(e => e.Employeeid == 10)
上記では、id = 10のレコードが存在しないため、例外がスローされます。null例外を回避するには、FirstOrDefault()
ではなくを使用する必要がありますFirst()
。
注:null値を返せないことが確実である場合にのみ、First()
/ を使用Single()
できます。
どちらの関数でも、SingleOrDefault()またはFirstOrDefault()を使用してnull例外を処理します。レコードが見つからない場合はnullを返します。