简体   繁体   English

根据带有linq的Id列表选择多个记录

[英]Select multiple records based on list of Id's with linq

I have a list containing Id's of my UserProfile table. 我有一个包含我的UserProfile表的Id的列表。 How can i select all UserProfiles based on the list of Id's i got in a var using LINQ ? 如何根据使用LINQvar获得的Id列表选择所有UserProfiles

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

I got stuck right here. 我被困在这里。 I can do this using for loops etc. But I'd rather do this with LINQ . 我可以使用for循环等来做这个。但我宁愿用LINQ做这个。

You can use Contains() for that. 你可以使用Contains() It will feel a little backwards when you're really trying to produce an IN clause, but this should do it: 当你真正尝试生成一个IN子句时,它会感觉有点倒退,但这应该做到:

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

I'm also assuming that each UserProfile record is going to have an int Id field. 我还假设每个UserProfile记录都有一个int Id字段。 If that's not the case you'll have to adjust accordingly. 如果不是这种情况,则必须相应调整。

Solution with .Where and .Contains has complexity of O(N square). 使用.Where和.Contains的解决方案具有O(N平方)的复杂度。 Simple .Join should have a lot better performance (close to O(N) due to hashing). 简单.Join应该有更好的性能(由于散列接近O(N))。 So the correct code is: 所以正确的代码是:

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

And now result of my measurement. 现在我的测量结果。 I generated 100 000 UserProfiles and 100 000 ids. 我生成了10万个UserProfiles和10万个ID。 Join took 32ms and .Where with .Contains took 2 minutes and 19 seconds! 加入花了32毫秒和。在哪里.Contains用了2分19秒! I used pure IEnumerable for this testing to prove my statement. 我使用纯IEnumerable进行此测试来证明我的陈述。 If you use List instead of IEnumerable, .Where and .Contains will be faster. 如果你使用List而不是IEnumerable,。Where和.Contains会更快。 Anyway the difference is significant. 无论如何,差异是显着的。 The fastest .Where .Contains is with Set<>. 最快的.Where .Contains是Set <>。 All it depends on complexity of underlying coletions for .Contains. 所有这一切都取决于.Contains的基础coletions的复杂性。 Look at this post to learn about linq complexity.Look at my test sample below: 看看这篇文章 ,了解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};
        }
    }

Console output: 控制台输出:

Elapsed .Join time: 00:00:00.0322546 经历时间:00:00:00.0322546

Elapsed .Where .Contains time: 00:02:19.4072107 Elapsed .Where。包含时间:00:02:19.4072107

Nice answers abowe, but don't forget one IMPORTANT thing - they provide different results! 很好的答案abowe,但不要忘记一个重要的事情 - 他们提供不同的结果!

  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();

This will return 2 rows from DB (and this could be correct, if you just want a distinct sorted list of users) 这将从DB返回2行(如果您只想要一个不同的用户排序列表,这可能是正确的)

BUT in many cases, you could want an unsorted list of results. 在许多情况下,您可能需要一个未排序的结果列表。 You always have to think about it like about a SQL query. 你总是要考虑一下SQL查询。 Please see the example with eshop shopping cart to illustrate what's going on: 请参阅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();

This will return 5 results from DB. 这将返回DB的5个结果。 Using 'contains' would be wrong in this case. 在这种情况下使用'contains'会出错。

That should be simple. 这应该很简单。 Try this: 试试这个:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM