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


122

我有一个包含UserProfile表ID的列表。我如何可以选择所有UserProfiles的基于身份的名单我在得到上var使用LINQ

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

我被困在这里。我可以使用for循环等执行此操作。但是,我宁愿使用LINQ


4
搜索和查找是两件不同的事情。但是,既然您可以通过互联网俯瞰我的肩膀,您能否告诉我您如何知道我没有搜索?等等别告诉!你看对了吗 完全是我的观点。
Yustme,2013年

5
提出问题要比进行搜索花费更多的时间。下一次只承担“他/她”做了搜索或10
Yustme

2
这仍然引起了很多关注,因此我想我要指出的是,ReSharper在建议将迭代代码转换为LINQ语句的位置方面做得很好。对于刚接触LINQ的人来说,仅是为此目的,它可能是必不可少的工具。
Yuck

Answers:


205

您可以使用Contains()它。当您真正尝试生成IN子句时,会感到有些倒退,但是应该这样做:

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

我还假设每个UserProfile记录将有一个int Id字段。如果不是这种情况,则必须进行相应调整。


嗨,是的,用户个人资料记录包含ID。所以以某种方式我会做类似t => t.id == idList.Contains(id)的事情吗?
Yustme

Contains()id如果您按照我在答案中所写的那样使用每个值,将处理该相等性检查。==当您尝试将一组(数组)的项目与另一组(数据库表)的项目进行比较时,无需在任何地方显式编写。
Yuck

很好的问题是,t保存了UserProfile的整个对象,而idList仅包含int的对象。编译器抱怨某些东西,但是我设法解决了。谢谢。
Yustme

1
@Yuck-功能超时,对我不起作用!禁用了延迟加载,但仍然失败。
bhuvin

1
我收到“无法将lambda表达式转换为类型'int',因为它不是委托类型”。如何解决?
斯蒂安

90

使用.where和.contains的解决方案具有O(N square)的复杂度。简单的.Join应该具有更好的性能(由于哈希,接近O(N))。因此正确的代码是:

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

现在是我的测量结果。我生成了100 000个UserProfiles和100 000个ID。Join花了32毫秒,而.Where和.Contains花了2分19秒!我在测试中使用了纯IEnumerable来证明我的陈述。如果使用List而不是IEnumerable,则.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年

好的,这是您感兴趣的计时:列表花了13.1秒,HashSet花了0.7毫秒!因此,仅在HashSet情况下(.contains的复杂度为O(1)),. where.contains才是最佳的。在其他情况下,.Join会更好
David Gregor

5
我得到Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator.使用LINQ2SQL的DataContext时错误。
Mayank Raichura,2016年

3
@Yustme-性能始终是一个考虑因素。(我讨厌成为“这应该是一个可以接受的答案”的家伙,但是...)
jleach

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

这将从数据库返回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();

这将从数据库返回5个结果。在这种情况下,使用“包含”将是错误的。


By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.