我有一个包含我UserProfile
表的 ID 的列表。如何UserProfiles
根据我在var
using中获得的 ID 列表选择所有LINQ
?
var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(......);
我就卡在这里了。我可以使用 for 循环等来做到这一点。但我宁愿用LINQ
.
你可以使用Contains()
它。当你真的试图产生一个IN
子句时,它会感觉有点倒退,但应该这样做:
var userProfiles = _dataContext.UserProfile
.Where(t => idList.Contains(t.Id));
我还假设每条UserProfile
记录都会有一个int
Id
字段。如果不是这种情况,您将不得不相应地进行调整。
.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
不错的答案,但不要忘记一件重要的事情 - 它们提供不同的结果!
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 个结果。在这种情况下,使用“包含”是错误的。
那应该很简单。试试这个:
var idList = new int[1, 2, 3, 4, 5];
var userProfiles = _dataContext.UserProfile.Where(e => idList.Contains(e));