1つのアイテムを選択するLinqコード


105

一致するアイテムを1つ選択するために、このようなコードをたくさん書いている

var item = (from x in Items where x.Id == 123 select x).First();

それを行うためのよりクリーンな方法はありますか、またはこれは私が得るつもりのように簡潔ですか?

編集:「linq構文を使用したよりクリーンな方法」と言っているはずです。私はすでにラムダ構文を知っていて、これが実際に唯一の方法であるように見え始めています。しかし、私はいくつかの有用な情報を得たので、答えてくれたみんなに感謝します。


5
個人的に私は避けるSingle()SingleOrDefault()、私が知っていればデータがあるため、(その制約を持つデータベースなどから例えば)すでにユニークであるSingle()ことが可能重複を見つけるために、リストの残りの部分をスキャンする力が、それは私です。この時点で一意性を強制する必要があるSingle()場合は、First()ファミリーを使用します。そうでない場合は、ファミリーを使用します。
ジェームズマイケルヘア

回答:


176

linqクエリ構文がどれだけ好きかによって、次のような拡張メソッドを直接使用できます。

var item = Items.First(i => i.Id == 123);

リストが空の場合にエラーをスローしたくない場合はFirstOrDefault、要素タイプのデフォルト値(null参照タイプの場合)を返すuse を使用します。

var item = Items.FirstOrDefault(i => i.Id == 123);

if (item != null)
{
    // found it
}

Single()SingleOrDefault()にも使用することができますが、データベースか何かから読んでいる場合は、すでに保証は、それはそこに任意の重複をだとスローかどうかを確認するために、リストをスキャンしているとして、私は気にしないだろう一意性ということができます。 First()そしてFirstOrDefault()彼らは、より効率的であるので、最初の試合でストップ。

First()Single()家族のうち、ここで彼らが投げます:

  • First() -空/見つからない場合はスローし、重複する場合はスローしません
  • FirstOrDefault() -空/見つからない場合はデフォルトを返し、重複する場合はスローしません
  • Single() -空/見つからない場合にスロー、重複が存在する場合にスロー
  • SingleOrDefault() -空/見つからない場合はデフォルトを返し、重複が存在する場合はスローします

1
そこには2つの等号がないと思います。する必要がありますi.Id == 123
davehale23

18

FirstOrDefaultまたはSingleOrDefaultは、シナリオに応じて、また、一致が0であるか複数であるかを処理するかどうかによって、役立つ場合があります。

FirstOrDefault:シーケンスの最初の要素、または要素が見つからない場合のデフォルト値を返します。

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

これがlinqの「from」クエリでどのように機能するかはわかりませんが、ラムダ構文では次のようになります。

var item1 = Items.FirstOrDefault(x => x.Id == 123);
var item2 = Items.SingleOrDefault(x => x.Id == 123);

DB時間に関して最も効率的なのはどれですか?varcharがある場合、完全一致が必要ですが、一致しない可能性はありますか?
Piotr Kula

2
受け入れられた回答はこれで完全に対処しますが、基本的にFirstOrDefaultは一致が見つかるとすぐに停止しますが、SingleOrDefaultはリスト全体を調べて、一致が1つだけであることを確認する必要があります。
stuartd '28

12

これらは、推奨される方法です。

var item = Items.SingleOrDefault(x => x.Id == 123);

または

var item = Items.Single(x => x.Id == 123);

ありがとう-したがって、この状況ではlinq表記がなく、ラムダを使用する必要がありますか?
Mikey Hogarth

それはかなり良いです。私は実際にlinqをあまり使用していなかったので、これらの方法を知っていたのかどうかはわかりません。
wageoghe

1
単一のメソッドは、戻り値が一意であることを確認します。したがって、コレクションが大きい場合は、多くの時間がかかる可能性があります。最初のメソッドは、述語に一致する最初の要素を返すだけです。
meziantou 2011年

@wageoghe Jamesの回答ではlinqを使用していません-SingleおよびSingleOrDefaultメソッドはIEnumerable実装の一部です。
Mikey Hogarth

12

誰かの生活を楽にするために、ラムダ式を使用したlinqクエリ

(from x in Items where x.Id == 123 select x).FirstOrDefault();

その結果、SQLクエリが発生します select top (1)


9

それはこれに凝縮することができます。

var item = Items.First(x => x.Id == 123);

クエリは現在、列挙型内のすべての結果(複数ある場合もあります)を収集してから、そのセットから最初の結果を取得し、必要以上の作業を行っています。

Single / SingleOrDefaultは価値がありますが、コレクション全体を反復処理し、一致を選択することに加えて、一致が一意であることを確認する場合のみです。First / FirstOrDefaultは、実際に存在する重複の数に関係なく、最初の一致を取得して終了します。


4

拡張メソッド構文を使用できます。

var item = Items.Select(x => x.Id == 123).FirstOrDefault();

それ以外に、独自の「First」および「FirstOrDefault」拡張メソッドを作成せずに、どれだけ簡潔にできるかはわかりません。


これは意図された動作ではないと思います。このSelect命令は、Itemの各要素に1つずつあるブールのコレクションを返します(実際には返さないが、戻りは選択されます)。これは、アイテムとして返される最初のもので、単純にブールになります。クリス・ハノンの溶液を使用し
レオナルドDAGA

おそらく、すでに述べられているとはWhere対照的にSelect、ということですが、この答えは正しくありません。c#で選択すると、結果がIEnumerable <bool>に変更されるboolため、最初の項目のを取得しますx.Id == 123
bradlis7

2

私がうまくいったことを教えてあげましょう:

int id = int.Parse(insertItem.OwnerTableView.DataKeyValues[insertItem.ItemIndex]["id_usuario"].ToString());

var query = user.First(x => x.id_usuario == id);
tbUsername.Text = query.username;
tbEmail.Text = query.email;
tbPassword.Text = query.password;

私のIDは、クエリを実行する行です。この場合、radGridから取得し、それを使用してクエリを実行しましたが、このクエリは行を返し、クエリから取得した値をテキストボックスなどに割り当てることができます。 、私はそれらをテキストボックスに割り当てる必要がありました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.