动态LINQ子查询 [英] Dynamic LINQ Sub Query

查看:53
本文介绍了动态LINQ子查询的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有要动态生成的LINQ查询:

I have LINQ query that I want to generate dynamically:

var groupData =
    from l in data
    group l by l.Field1 into field1Group
    select new MenuItem()
    {
        Key = field1Group.Key,
        Count = field1Group.Count(),
        Items = (from k in field1Group
                 group k by k.Field2 into field2Group
                 select new MenuItem()
                 {
                     Key = field2Group.Key,
                     Count = field2Group.Count()
                 }).ToList()
    };

最终目标是能够按字段的任意组合对数据进行动态分组,而对嵌套查询没有限制.

The ultimate goal is to be able to dynamically group the data by any combination of fields with no limit on the nested queries.

我可以达到第一级,但是我在嵌套子查询中苦苦挣扎:

I can get as far as the first level but I'm struggling with the nested sub queries:

string field1 = "Field1";
string field2 = "Field2";

var groupDataD =
    data.
    GroupBy(field1, "it").
    Select("new ( it.Key, it.Count() as Count )");

使用链式动态LINQ可能吗?还是有更好的方法来实现这一目标?

Is this possible with chained dynamic LINQ? Or is there a better way to achieve this?

推荐答案

以下内容应该可以工作(尽管我个人更希望避免使用此类代码):

The following should work (though personally I would rather avoid using such code):

  1. 按照此答案ParseAggregate

Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
{
   // Change starts here
   var originalIt = it;
   var originalOuterIt = outerIt;
   // Change ends here

   outerIt = it;
   ParameterExpression innerIt = Expression.Parameter(elementType, elementType.Name);
   it = innerIt;
   Expression[] args = ParseArgumentList();

   // Change starts here
   it = originalIt;
   outerIt = originalOuterIt;
   // Change ends here

   ...
}

  • SelectGroupByToList添加到IEnumerableSignatures中,并在ParseAggregate中添加相应的条件,如

  • Add Select, GroupBy, ToList into IEnumerableSignatures, and respective conditions in ParseAggregate, as explained in this answer:

    interface IEnumerableSignatures
    {
      ...
      void GroupBy(object selector);
      void Select(object selector);
      void ToList();
      ...
    }
    
    Expression ParseAggregate(Expression instance, Type elementType, string methodName, int errorPos)
    {
       ...
       if (signature.Name == "Min" || 
           signature.Name == "Max" || 
           signature.Name == "GroupBy" || 
           signature.Name == "Select")
       ...
    }
    

  • 最后,您的查询将是:

  • Finally, Your query would be:

    string field1 = "Field1";
    string field2 = "Field2";
    
    var result =
        data
        .GroupBy(field1, "it")
        .Select($@"new ( 
           it.Key,
           it.Count() as Count,
           it.GroupBy({field2})
             .Select(new (it.Key, it.Count() as Count))
             .ToList() as Items
        )");
    

    请注意,在父查询和子查询中使用的"it"拥有不同的实例.我尝试利用"outerIt"来克服这种合并问题,但不幸的是没有成功(但是也许您会成功?也许 1 2 会有所帮助)

    Note that "it" holds a different instance when used in the parent query vs. the subquery. I tried to take advantage of "outerIt" to overcome this conflation, but unfortunately without success (but maybe you'd succeed? maybe 1, 2 would help)

    一个简单的示例,供将来参考:

    A simple example for future reference:

    public class Person
    {
        public string State { get; set; }
        public int Age { get; set; }
    }
    public static Main()
    {
        var persons = new List<Person>
        {
           new Person { State = "CA", Age = 20 },
           new Person { State = "CA", Age = 20 },
           new Person { State = "CA", Age = 30 },
           new Person { State = "WA", Age = 60 },
           new Person { State = "WA", Age = 70 },
        };
        var result = persons
            .GroupBy("State", "it")
            .Select(@"new ( 
               it.Key,
               it.Count() as Count,
               it.GroupBy(Age)
                 .Select(new (it.Key, it.Count() as Count))
                 .ToList() as Items
            )");
         foreach (dynamic group in result)
         {
             Console.WriteLine($"Group.Key: {group.Key}");
             foreach (dynamic subGroup in group.Items)
             {
                 Console.WriteLine($"SubGroup.Key: {subGroup.Key}");
                 Console.WriteLine($"SubGroup.Count: {subGroup.Count}");
             }
         }
    }
    

  • 这篇关于动态LINQ子查询的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆