如何在运行时动态地组合一组LINQ查询?
本文关键字:合一 LINQ 查询 组合 运行时 动态 | 更新日期: 2023-09-27 18:04:08
编辑:试图使我的问题更清楚一点。
我正在尝试构建一个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来强制执行。
您的代码可以重构,以获得多个用户列表:
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);
现在问题变成了多个列表的交集:
var intersection = listOfListsOfUsers.Aggregate((previousList, nextList) => previousList.Intersect(nextList));
看起来你只是想要一个User
的列表:
var list = new List<User>();
然后你可以添加每组结果,当你得到它们:
list.AddRange(someUsers);
如果User
是一个可以对其执行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 allboooleanstrue 做到了这一点。我给它赋了一个非空值,让Resharper不再唠叨我。我遇到的第二个问题是著名的闭包问题。我使用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语句替换外部变量(allboooleantrue)的内容。其他迭代执行一个交集。这里有点粗糙,但这似乎有效(到目前为止)。我想我应该使用表达式树,但那是另一天。
对不起,我改变了我的代码周围的原始帖子,但我死累了,从我的测试类复制了这一点。