如何在运行时动态组合一组 LINQ 查询?
How can I dynamically combine a set of LINQ queries at runtime?
编辑:试图让我的问题更清楚一点。
我正在尝试构建一个 LINQ 表达式,它是几个 LINQ 语句的交集。现在,我可以手动将两个语句交叉在一起,并且得到了想要的结果。
var results =
context.UserBooleanAttributes.Where(x => x.UserAttributeID == 1 && x.Value).Select(a => a.User)
.Intersect(
context.UserBooleanAttributes.Where(y => y.UserAttributeID == 2 && y.Value).Select(b => b.User)
);
Assert.Equal(100,results.Count());
我的目标是动态构建它,例如使用 for 循环。因为我使用的是 LINQ,所以我想推迟执行,直到我实际调用某些强制执行的 results。
看来您只需要 User
:
的列表
var list = new List<User>();
然后你可以添加每组结果,当你得到它们时:
list.AddRange(someUsers);
如果 User
是一个 class,您可以对其执行 Intersect
,并且您只需要不同的值(您的代码中似乎就是这种情况),请考虑这样做一口气,最后调用 Distinct()
:
var attrIDs = Enumerable.Range(1, xTimes);
list.AddRange(context.UserBooleanAttributes
.Where(x => attrIDs.Contains(x.UserAttributeID) && x.Value)
.Select(a => a.User)
.Distinct());
这里有几个问题。首先是我需要一种方法来声明我的匿名变量以在循环外使用。我通过使用 IQueryable allBooleansTrue 来做到这一点。我给它分配了一个非空值,让 Resharper 停止烦扰我。第二个问题是我 运行 进入了著名的 closures issue。我使用 int copy = i
解决了这个问题
IQueryable<User> allBooleansTrue = new List<User>().AsQueryable();
for (int i = 1; i <= numBools; i++)
{
int copy = i; //workaround to prevent closures using reference
var q = context.UserBooleanAttributes.Where(y => y.UserAttributeID == copy && y.Value)
.Select(a => a.User);
if (i == 1)
allBooleansTrue = q;
else
allBooleansTrue = allBooleansTrue.Intersect(q);
第一次迭代用 LINQ 语句替换了我的外部变量 (allBooleansTrue) 的内容。其他迭代执行交集。这里有点 hacky,但这似乎有效(到目前为止)。我想我应该使用表达式树,但那是另一天的事了。
抱歉,我为原来的 post 稍微更改了我的代码,但我实在是太累了,从我的测试 class.
中复制了这个
您的代码可以重构,以获取多个用户列表:
IEnumerable<IEnumerable<User>> GetListOfListsOfUsers(int xTimes)
{
for (int i = 1; i <= xTimes; i++)
{
var someUsers = context.UserBooleanAttributes
.Where(x => x.UserAttributeID == i && x.Value == true)
.Select(a => a.User);
yield return someUsers;
}
}
var listOfListsOfUsers = GetListOfListsOfUsers(xTimes);
问题现在变成了intersection of multiple lists:
var intersection = listOfListsOfUsers.Aggregate((previousList, nextList) => previousList.Intersect(nextList));
编辑:试图让我的问题更清楚一点。
我正在尝试构建一个 LINQ 表达式,它是几个 LINQ 语句的交集。现在,我可以手动将两个语句交叉在一起,并且得到了想要的结果。
var results =
context.UserBooleanAttributes.Where(x => x.UserAttributeID == 1 && x.Value).Select(a => a.User)
.Intersect(
context.UserBooleanAttributes.Where(y => y.UserAttributeID == 2 && y.Value).Select(b => b.User)
);
Assert.Equal(100,results.Count());
我的目标是动态构建它,例如使用 for 循环。因为我使用的是 LINQ,所以我想推迟执行,直到我实际调用某些强制执行的 results。
看来您只需要 User
:
var list = new List<User>();
然后你可以添加每组结果,当你得到它们时:
list.AddRange(someUsers);
如果 User
是一个 class,您可以对其执行 Intersect
,并且您只需要不同的值(您的代码中似乎就是这种情况),请考虑这样做一口气,最后调用 Distinct()
:
var attrIDs = Enumerable.Range(1, xTimes);
list.AddRange(context.UserBooleanAttributes
.Where(x => attrIDs.Contains(x.UserAttributeID) && x.Value)
.Select(a => a.User)
.Distinct());
这里有几个问题。首先是我需要一种方法来声明我的匿名变量以在循环外使用。我通过使用 IQueryable allBooleansTrue 来做到这一点。我给它分配了一个非空值,让 Resharper 停止烦扰我。第二个问题是我 运行 进入了著名的 closures issue。我使用 int copy = i
解决了这个问题 IQueryable<User> allBooleansTrue = new List<User>().AsQueryable();
for (int i = 1; i <= numBools; i++)
{
int copy = i; //workaround to prevent closures using reference
var q = context.UserBooleanAttributes.Where(y => y.UserAttributeID == copy && y.Value)
.Select(a => a.User);
if (i == 1)
allBooleansTrue = q;
else
allBooleansTrue = allBooleansTrue.Intersect(q);
第一次迭代用 LINQ 语句替换了我的外部变量 (allBooleansTrue) 的内容。其他迭代执行交集。这里有点 hacky,但这似乎有效(到目前为止)。我想我应该使用表达式树,但那是另一天的事了。
抱歉,我为原来的 post 稍微更改了我的代码,但我实在是太累了,从我的测试 class.
中复制了这个您的代码可以重构,以获取多个用户列表:
IEnumerable<IEnumerable<User>> GetListOfListsOfUsers(int xTimes)
{
for (int i = 1; i <= xTimes; i++)
{
var someUsers = context.UserBooleanAttributes
.Where(x => x.UserAttributeID == i && x.Value == true)
.Select(a => a.User);
yield return someUsers;
}
}
var listOfListsOfUsers = GetListOfListsOfUsers(xTimes);
问题现在变成了intersection of multiple lists:
var intersection = listOfListsOfUsers.Aggregate((previousList, nextList) => previousList.Intersect(nextList));