LINQ:フィルタリング基準でSingleOrDefaultとFirstOrDefault()を使用する場合


506

IEnumerable拡張メソッドSingleOrDefault()FirstOrDefault()

MSDNのドキュメントSingleOrDefault

シーケンスの唯一の要素、またはシーケンスが空の場合はデフォルト値を返します。シーケンスに複数の要素がある場合、このメソッドは例外をスローします。

一方FirstOrDefault、MSDNから(おそらく、OrderBy()または、OrderByDescending()またはまったく使用しない 場合)、

シーケンスの最初の要素を返します

いくつかのクエリ例を検討してください。これら2つのメソッドをいつ使用するかは必ずしも明確ではありません。

var someCust = db.Customers
.SingleOrDefault(c=>c.ID == 5); //unlikely(?) to be more than one, but technically COULD BE

var bobbyCust = db.Customers
.FirstOrDefault(c=>c.FirstName == "Bobby"); //clearly could be one or many, so use First?

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or does it matter?

質問

あなたはどのような規則に従うか、お勧めします使用することを決定する際SingleOrDefault()FirstOrDefault()、あなたのLINQクエリでは?

回答:


466

を使用する場合SingleOrDefaultは常に、クエリの結果が最大で1つの結果になることを明確に示します。一方、FirstOrDefaultを使用すると、クエリは任意の量の結果を返すことができますが、最初の結果のみが必要であると述べます。

私は個人的にセマンティクスが非常に異なっていると感じ、期待される結果に応じて適切なセマンティクスを使用すると、読みやすさが向上します。


164
非常に重要な違いは、複数の要素を持つシーケンスでSingleOrDefaultを使用すると、例外がスローされることです。
Kamran Bigdely 2014年

17
@kamiが例外をスローしなかった場合、FirstOrDefaultとまったく同じになります。例外は、それをSingleOrDefaultにするものです。それを育てる良い点は、違いの棺桶に釘を打つこと。
Fabio S.

17
FirstOrDefaultは、パフォーマンスの点で、SingleOrDefaultの約10倍の速さで動作し、9,000,000要素のList <MyClass>を使用しており、クラスには2つの整数が含まれ、Funcにはこれら2つの整数の検索が含まれています。ループで200回検索すると、var v = list.SingleOrDefault(x => x.Id1 == i && x.Id2 == i);で22秒かかりました。およびvar v = list.FirstOrDefault(x => x.Id1 == i && x.Id2 == i); 約3秒

6
@BitsandBytesHandymanシーケンスに複数のアイテムが含まれているときにSignleOrDefaultが例外をスローしなかった場合、FirstOrDefaultとまったく同じように動作しません。FirstOrDefaultは最初のアイテムを返します。シーケンスが空の場合はnullを返します。SingleOrDefaultは、例外をまったくスローすることなく、唯一のアイテムを返すか、シーケンスが空の場合、またはシーケンスに複数のアイテムが含まれる場合はnullを返します。
Thanasis Ioannidis

2
@RSWはい、私はそれを認識しています。私のコメントを注意深く読んで、私はSingleOrDefaultが何をすべきかではなく、何をすべきかを言っていました。しかし、もちろん、それがすべきことは非常に主観的です。私にとって、「SomethingOrDefault」パターンは、「Something」の値を取得することを意味します。「何か」が値を返せない場合は、デフォルト値を返します。つまり、「何か」が例外をスローする場合でも、デフォルト値が返されます。したがって、Singleが例外をスローする場合、私の観点では、SingleOrDefaultはデフォルト値を返す必要があります。
Thanasis Ioannidis

585

結果セットが0レコードを返す場合:

  • SingleOrDefault タイプのデフォルト値を返します(たとえば、intのデフォルトは0です)
  • FirstOrDefault タイプのデフォルト値を返します

結果セットが1つのレコードを返す場合:

  • SingleOrDefault そのレコードを返します
  • FirstOrDefault そのレコードを返します

結果セットが多くのレコードを返す場合:

  • SingleOrDefault 例外を投げる
  • FirstOrDefault 最初のレコードを返します

結論:

結果セットに多数のレコードが含まれている場合に例外をスローする場合は、を使用しますSingleOrDefault

結果セットに何が含まれていても常に1つのレコードが必要な場合は、 FirstOrDefault


6
実際に例外が必要になることはほとんどないので、ほとんどの場合FirstOrDefaultが優先されます。私は、それほど頻繁ではないケースが存在することを知っています。
MikeKulls、

FirstOrDefault最初のレコードが返されるということは、新しいレコード(最後)/古いレコード(最初)を意味しますか?
2014年

@Duk、それはレコードをどのようにソートするかによります。FirstOrDefaultを呼び出す前に、OrderBy()やOrderByDescending()などを使用できます。OPのコード例を参照してください。
2014年

5
私もこの答えが好きです。特に、まれに発生しないというふりをするのではなく、他の場所でそのまれなケースを適切に処理しようとするため、実際に例外をスローしたい場合があります。例外が必要な場合は、これを明確に述べ、システム全体をより堅牢にするために、他の人にケースを処理することを強制します。
Francis Rodgers

わかりやすいように明記しています。
Nirav Vasoya

244

有る

  • 意味の違い
  • パフォーマンスの違い

ふたつの間に。

意味の違い:

  • FirstOrDefault 複数の可能性のある最初の項目を返します(存在しない場合はデフォルト)。
  • SingleOrDefault単一のアイテムがあると想定し、それを返します(存在しない場合はデフォルト)。複数のアイテムは契約違反であり、例外がスローされます。

パフォーマンスの違い

  • FirstOrDefault通常はより高速で、要素が見つかるまで反復し、見つからない場合は列挙型全体を反復するだけです。多くの場合、アイテムを見つける可能性が高くなります。

  • SingleOrDefault要素が1つしかないかどうかを確認する必要があるため、常に列挙可能な全体を繰り返します。正確には、2番目の要素が見つかるまで反復し、例外をスローします。しかし、ほとんどの場合、2番目の要素はありません。

結論

  • 使用FirstOrDefaultあなたがそこにあるどのように多くのアイテムを気にしない場合、またはあなたが(例えば非常に大規模なコレクションで)一意性をチェックする余裕がないとき。コレクションにアイテムを追加する際に一意性をチェックする場合、それらのアイテムを検索するときに再度チェックするのはコストがかかりすぎる可能性があります。

  • SingleOrDefaultパフォーマンスをあまり気にする必要がなく、単一の項目の前提が読者に明確であり、実行時にチェックされることを確認したい場合に使用します。

実際には、パフォーマンスを向上させるために、単一のアイテムを想定する場合でもFirst/をFirstOrDefault頻繁に使用します。Single/ SingleOrDefaultは読みやすさ(単一の項目の仮定を示すため)と安定性(チェックするため)を改善し、適切に使用できることを覚えておく必要があります。


16
+1 「または一意性をチェックする余裕がない場合(非常に大きなコレクションなど)」。これを探していました。クエリを作成するときではなく、挿入時または設計時に、一意性強制することもできます!
Nawaz 2013

SingleOrDefaultLinq to Objectsを使用すると、多くのオブジェクトを反復処理することを想像できSingleOrDefaultますが、たとえば、Linqがデータベースと通信している場合、最大2つの項目を反復処理する必要はありませんか?ただ疑問に思う..
Memet Olsen 2013

3
LINQ to SQLは2つのコード唾を考えてみましょう@memetolsen - FirstOrDefaultトップ1. SingleOrDefaultがトップ2.使用しています使用しています
ジム・ウーリー

@JimWooley私は「列挙可能」という言葉を誤解したと思います。ステファンはC#を意味すると思いましたEnumerable
Memet Olsen 2013

1
@memetolsenは元の回答に関しては正しいです。あなたのコメントはデータベースを参照していたので、プロバイダーから何が起こるかを提供しました。.Netコードは2つの値のみを反復処理しますが、データベースは、条件を満たす2番目のレコードに到達するまで、必要な数のレコードにアクセスします。
ジムウーリー2013年

76

SQLで変換されたFirstOrDefaultはTOP 1レコードを実行し、SingleOrDefaultはTOP 2レコードを実行することについて誰も言及していません。


3
LinqPadとVSを使用してSingleOrDefaultを実行したとき、SELECT TOP 2を取得できませんでした。FirstOrDefaultを使用すると、SELECT TOP 1を取得できましたが、SELECT TOP 2を取得できないと言う限り
Jamie R Rytlewski

ちょっと私もlinqpadで試されており、SQLクエリはすべての行を完全にフェッチするので私を恐れました どのようにしてこれが起こるかわかりませんか?
AnyOne 2012年

1
これは、使用するLINQプロバイダーに完全に依存します。たとえば、LINQ to SQLおよびLINQ to Entitiesは、さまざまな方法でSQLに変換できます。私は、IQのMySQLプロバイダとLINQPadを試みたが、FirstOrDefault()追加しLIMIT 0,1ながら、SingleOrDefault()何も加えません。
ルーカス

1
EF Core 2.1は、FirstOrDefaultをSELECT TOP(1)に、SingleOrDefaultをSELECT TOP(2)に
変換します

19

LINQ-> SQLの場合:

SingleOrDefault

  • 「select * from users where userid = 1」のようなクエリを生成します
  • 一致するレコードを選択し、複数のレコードが見つかった場合は例外をスローします
  • 主/一意キー列に基づいてデータをフェッチする場合に使用します

FirstOrDefault

  • 「userid = 1のユーザーから上位1 *を選択」のようなクエリを生成します
  • 最初に一致する行を選択
  • 非主キー/一意キー列に基づいてデータをフェッチする場合に使用します

SingleOrDefaultから "Select all matching rows"を削除する必要があると思います
Saim Abdullah

10

SingleOrDefault私のロジックでは、結果が0または1になることが示されている状況で使用します。それ以上ある場合は、エラー状況であるため、役立ちます。


3
SingleOrDefault()は、結果セットに適切なフィルタリングを適用していない場合、または基になるデータの重複に関する問題がある場合を強調表示することがよくあります。多くの場合、First()メソッドではなくSingle()およびSingleOrDefault()を使用しています。
TimS 2012年

列挙型が大きい場合にLINQ to ObjectsのSingle()およびSingleOrDefault()のパフォーマンスに影響がありますが、データベース(SQL Serverなど)と通信する場合、上位2呼び出しが行われ、インデックスが正しく設定されている場合呼び出しは高価であってはならず、First()またはFirstOrDefault()を呼び出すときに間違った重複をとることによって他のデータの問題を引き起こす可能性の代わりに、速く失敗してデータの問題を見つけたいと思います。
heartlandcoder、2015

5

SingleOrDefault:「最大で」クエリまたはデフォルトに一致する1つのアイテムがあることを言っているFirstOrDefault:「少なくとも」クエリまたはデフォルトに一致する1つのアイテムがあることを言っている

次に選択する必要があるときは、声を出して言ってください。あなたはおそらく賢明に選択するでしょう。:)


5
実際に結果がないことは完全に許容できるFirstOrDefault. More correctly: FirstOrDefault` =の結果の数の使用ですが、私は最初の結果のみを気にします。結果がない場合もあります。 SingleOrDefault= 1または0の結果があります。それ以上ある場合は、どこかにエラーがあることを意味します。 First=少なくとも1つの結果があり、それが欲しい。 Single=ちょうど1つの結果があり、それ以上でもそれ以下でもない、そして私はそれを望んでいる。
Davy8、2011年

4

あなたの場合、私は以下を使用します:

select by ID == 5:ここではSingleOrDefaultを使用しても問題ありません。1つ(またはなし)のエンティティを想定しているため、ID 5のエンティティが複数ある場合は、何か問題があり、間違いなく例外に値します。

名が「Bobby」と等しい人を検索する場合、複数存在する可能性があるので(かなり考えられるかもしれません)、SingleもFirstも使用せず、Where操作で選択するだけです(「Bobby」が多すぎる場合エンティティ、ユーザーは検索を絞り込むか、返された結果の1つを選択する必要があります)

作成日による順序付けは、Where操作でも実行する必要があります(エンティティが1つしかない可能性が高いため、並べ替えはあまり役に立ちません;)ただし、これは、すべてのエンティティを並べ替えることを意味します。1つだけが必要な場合は、FirstOrDefaultを使用します。複数のエンティティを取得すると、シングルは毎回スローされます。


3
同意しません。データベースIDが主キーである場合、データベースはすでに一意性を適用しています。データベースがすべてのクエリでそのジョブを実行しているかどうかを確認するためにCPUサイクルを浪費することはばかげています。
ジョンヘンケル

4

どちらも要素演算子であり、シーケンスから単一の要素を選択するために使用されます。しかし、それらの間には小さな違いがあります。SingleOrDefault()演算子は、複数の要素が条件を満たす場合に例外をスローしますが、FirstOrDefault()は同じ要素に対して例外をスローしません。以下がその例です。

List<int> items = new List<int>() {9,10,9};
//Returns the first element of a sequence after satisfied the condition more than one elements
int result1 = items.Where(item => item == 9).FirstOrDefault();
//Throw the exception after satisfied the condition more than one elements
int result3 = items.Where(item => item == 9).SingleOrDefault();

2
「それらの間には小さな違いがあります」-それは重要です!
Nikhil Vartak

3

あなたの最後の例では:

var latestCust = db.Customers
.OrderByDescending(x=> x.CreatedOn)
.FirstOrDefault();//Single or First, or doesn't matter?

はい、そうです。使用しようとするSingleOrDefault()と、クエリの結果が複数のレコードになる場合、例外が発生します。安全に使用できる唯一の時間SingleOrDefault()は、結果が1つだけで、1つだけを期待している場合です...


そのとおりです。結果が0の場合、例外も発生します。
Dennis Rongo 2016年

1

私が理解しているように SingleOrDefault一意であることが保証されている、つまり主キーのようなDB制約によって強制されているデータをクエリしている場合は良いでしょう。

または、主キーを照会するより良い方法があります。

私のTableAccが持っていると仮定します

AccountNumber - Primary Key, integer
AccountName
AccountOpenedDate
AccountIsActive
etc.

とクエリしたいのでAccountNumber 987654

var data = datacontext.TableAcc.FirstOrDefault(obj => obj.AccountNumber == 987654);

1

私の意見でFirstOrDefaultは、たくさん使われすぎています。データをフィルタリングするほとんどの場合、論理条件に一致する要素のコレクション、またはユーザー、本、投稿などの一意の識別子による単一の一意の要素を返すことが期待されます。それはなぜそれがFirstOrDefault()コードのにおいであると言うことができるのか、それは何か問題があるからではなく、あまりにも頻繁に使用されているためです。このブログ投稿では、このトピックについて詳しく説明しています。ほとんどの場合、IMO SingleOrDefault()ははるかに優れた代替手段です。このため、この間違いに注意し、契約と期待を明確に表す最も適切な方法を使用してください。


-1

応答で見逃されている1つの事柄...

複数の結果がある場合、order byのないFirstOrDefaultは、サーバーで使用されたインデックス戦略に基づいて異なる結果を返す可能性があります。

個人的には、コードでFirstOrDefaultを見るのは我慢できません。なぜなら、私にとっては、開発者は結果を気にしていなかったからです。ただし、order by byを使用すると、最新/最も古いものを強制する方法として役立ちます。FirstOrDefaultを使用する不注意な開発者によって引き起こされる多くの問題を修正しなければなりませんでした。


-2

GitHubでさまざまなメソッドを使用する方法についてGoogleに問い合わせました。これは、各メソッドに対してGoogle検索クエリを実行し、クエリ「site:github.com file:cs ...」を使用して、クエリをgithub.comドメインと.csファイル拡張子に制限することで行われます。

First *メソッドは、Single *メソッドよりも一般的に使用されているようです。

| Method               | Results |
|----------------------|---------|
| FirstAsync           |     315 |
| SingleAsync          |     166 |
| FirstOrDefaultAsync  |     357 |
| SingleOrDefaultAsync |     237 |
| FirstOrDefault       |   17400 |
| SingleOrDefault      |    2950 |

-8

を使用FirstOrDefault(x=> x.ID == key)すると結果がはるかに速く取得できるのに、なぜ使用しているのか理解できませんFind(key)。テーブルの主キーを使用してクエリを実行する場合、経験則では常にを使用しますFind(key)。などのFirstOrDefaultような述語に使用する必要があります(x=> x.Username == username)

質問の見出しはDB上のlinqまたはList / IEnumerableなどのlinqに固有ではなかったため、これは反対票に値しませんでした。


1
どの名前空間にありFind()ますか?
p.campbell

教えて頂けますか?まだ答えを待っています。
デニー


「IEnumerable」という単語は、質問の本文の最初の行にあります。タイトルだけを読んで実際の質問ではなく、結果として間違った回答を投稿した場合、それはあなたの間違いであり、IMOに反対票を投じる正当な理由です。
F1Krazy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.