linqを使用したIDのリストに基づいて複数のレコードを選択します


122

UserProfileテーブルのIDを含むリストがあります。使用してUserProfiles取得したIDのリストに基づいてすべてを選択するにはどうすればよいですか?varLINQ

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(......);

ここで行き詰まりました。forループなどを使用してこれを行うことができます。ただし、これはで行いますLINQ


4
検索と発見は2つの異なるものです。しかし、インターネットを介して私の肩越しに見渡すことができるので、私が検索しなかったことをどのように知っているか教えていただけませんか?言わないで待って!あなたはそれを正しく見ましたか?私の要点。
ユストミー2013年

5
質問することは、検索するよりも時間がかかります。次回は、ちょうど仮定し「彼/彼女やった検索や10
Yustme

2
これはまだかなりの注目を集めているので、ReSharperは反復コードをLINQステートメントに変換できる場所を提案する非常に優れた仕事をしていると私は言及したいと思いました。LINQを初めて使用する人にとって、それはこの目的だけのために不可欠なツールです。
Yuck

回答:


205

Contains()そのために使用できます。実際にIN句を作成しようとすると、少し後ろ向きになりますが、これでうまくいくはずです。

var userProfiles = _dataContext.UserProfile
                               .Where(t => idList.Contains(t.Id));

また、各UserProfileレコードにはint Idフィールドがあると想定しています。そうでない場合は、それに応じて調整する必要があります。


こんにちは、ユーザープロファイルレコードにはIDが含まれています。したがって、どういうわけか私はt => t.id == idList.Contains(id)のようなことをしているでしょうか?
ユストミー2013年

Contains()id私が答えで書いたようにそれを使用すれば、各値の同等性チェックを処理します。==あるセット(配列)のアイテムを別のセット(データベーステーブル)と比較する場合、明示的にどこにも書き込む必要はありません。
Yuck

問題は、tがUserProfileのオブジェクト全体を保持し、idListに含まれるのはintのみであることです。コンパイラは何かについて不平を言ったが、私はそれをなんとか修正した。ありがとう。
Yustme、2013年

1
@Yuck-私にはうまくいきません、関数はタイムアウトしたと言います!遅延読み込みを無効にしても失敗する。
ブビン14

1
「ラムダ式はデリゲート型ではないため、型 'int'に変換できません」と表示されます。それを修正するには?
Stian

90

.Whereと.ContainsのソリューションはO(N平方)の複雑さを持っています。単純な.Joinは、パフォーマンスが大幅に向上するはずです(ハッシュによりO(N)に近い)。したがって、正しいコードは次のとおりです。

_dataContext.UserProfile.Join(idList, up => up.ID, id => id, (up, id) => up);

そして今、私の測定の結果。10万のユーザープロファイルと10万のIDを生成しました。参加には32ミリ秒かかり、.Containsでは2分19秒かかりました。このテストでは、純粋なIEnumerableを使用して自分の発言を証明しました。IEnumerableの代わりにListを使用すると、.Whereおよび.Containsの方が高速になります。とにかく違いは重要です。最速の.Where .ContainsはSet <>を使用します。すべては、.Containsの基礎となるコレクションの複雑さに依存します。linqの複雑さについては、この投稿をご覧ください。以下のテストサンプルをご覧ください。

    private static void Main(string[] args)
    {
        var userProfiles = GenerateUserProfiles();
        var idList = GenerateIds();
        var stopWatch = new Stopwatch();
        stopWatch.Start();
        userProfiles.Join(idList, up => up.ID, id => id, (up, id) => up).ToArray();
        Console.WriteLine("Elapsed .Join time: {0}", stopWatch.Elapsed);
        stopWatch.Restart();
        userProfiles.Where(up => idList.Contains(up.ID)).ToArray();
        Console.WriteLine("Elapsed .Where .Contains time: {0}", stopWatch.Elapsed);
        Console.ReadLine();
    }

    private static IEnumerable<int> GenerateIds()
    {
       // var result = new List<int>();
        for (int i = 100000; i > 0; i--)
        {
            yield return i;
        }
    }

    private static IEnumerable<UserProfile> GenerateUserProfiles()
    {
        for (int i = 0; i < 100000; i++)
        {
            yield return new UserProfile {ID = i};
        }
    }

コンソール出力:

経過。参加時間:00:00:00.0322546

経過。場所を含む:00:02:19.4072107


4
数字でそれを裏付けることができますか?
Yustme 2014年

ニース、しかし、がどのようなタイミングListで使用されるかを知りたくなります。+1
Yustme 2014年

OK、興味のあるタイミングは次のとおりです。リストには13.1秒かかり、HashSetには0.7秒かかりました。したがって、.Where .ContainsはHashSetの場合にのみ最適です(.Containsの複雑度はO(1)です)。他の場合では、.Joinの方が優れています
David Gregor

5
Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.LINQ2SQLデータコンテキストを使用するとエラーが発生します。
Mayank Raichura 2016年

3
@Yustme-パフォーマンスは常に考慮事項です。(私は「これは受け入れられる答えである必要があります」という人になり
たくあり

19

いい答えは避けられますが、重要なことを忘れないでください-それらは異なる結果を提供します!

  var idList = new int[1, 2, 2, 2, 2]; // same user is selected 4 times
  var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e)).ToList();

これにより、DBから2行が返されます(ユーザーの個別の並べ替えられたリストが必要な場合は、これが正しい場合もあります)。

しかし、多くの場合、ソートされていない結果のリストが必要になる可能性があります。SQLクエリと同じように常に考える必要があります。何が起こっているのかを説明するには、eshopショッピングカートの例をご覧ください。

  var priceListIDs = new int[1, 2, 2, 2, 2]; // user has bought 4 times item ID 2
  var shoppingCart = _dataContext.ShoppingCart
                     .Join(priceListIDs, sc => sc.PriceListID, pli => pli, (sc, pli) => sc)
                     .ToList();

これにより、DBから5つの結果が返されます。この場合、 'contains'を使用することは間違っています。


13

それは簡単なはずです。これを試して:

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e));
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.