如何在运行时动态地组合一组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来强制执行。

如何在运行时动态地组合一组LINQ查询?

您的代码可以重构,以获得多个用户列表:

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)的内容。其他迭代执行一个交集。这里有点粗糙,但这似乎有效(到目前为止)。我想我应该使用表达式树,但那是另一天。

对不起,我改变了我的代码周围的原始帖子,但我死累了,从我的测试类复制了这一点。