156

我有一个包含我UserProfile表的 ID 的列表。如何UserProfiles根据我在varusing中获得的 ID 列表选择所有LINQ

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

我就卡在这里了。我可以使用 for 循环等来做到这一点。但我宁愿用LINQ.

4

4 回答 4

258

你可以使用Contains()它。当你真的试图产生一个IN子句时,它会感觉有点倒退,但应该这样做:

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

我还假设每条UserProfile记录都会有一个int Id字段。如果不是这种情况,您将不得不相应地进行调整。

于 2013-05-29T21:53:50.043 回答
112

.Where 和 .Contains 的解决方案具有 O(N 平方) 的复杂度。简单的 .Join 应该有更好的性能(由于散列,接近 O(N))。所以正确的代码是:

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

现在是我的测量结果。我生成了 100 000 个用户配置文件和 100 000 个 ID。加入用了 32 毫秒,而 .Where 用 .Contains 用了 2 分 19 秒!我在这个测试中使用了纯 IEnumerable 来证明我的说法。如果使用 List 而不是 IEnumerable,.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

Elapsed .Where .包含时间:00:02:19.4072107

于 2014-11-03T14:26:44.100 回答
28

不错的答案,但不要忘记一件重要的事情 - 它们提供不同的结果!

  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 个结果。在这种情况下,使用“包含”是错误的。

于 2016-02-04T18:09:32.943 回答
14

那应该很简单。试试这个:

var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e));
于 2013-05-29T21:55:09.470 回答