如何使用动态linq核心根据另一个领域的条件进行选择和计数

问题描述

我正在使用 Entity FrameworkDynamic Linq Core 在运行时执行一些动态查询我有一个关于如何编写动态 linq 语句以输出计数列的问题,其中每一列都是另一个字段的字段项。

假设我有一个包含 3 列的表:ID、Gender 和 Age(假设它们只有 10 多岁)。

ID | Gender | Age
01 |   male |  20
02 | female |  30
... some thousands of rows

我想按年龄组计算每个性别(groupBy Gender)的人数。

[{Gender:"male","20": 120,"30": 200,"40": 300},{Gender:"female","20": 300,"40": 1000 }]

我尝试按年龄分组,但这并没有给出我想要的上述格式,因为每个性别和年龄组合都成为一个新的数组项。

var query = db.someDB
        .GroupBy("new(Gender,Age)")
        .Select("new(Key.Gender as Gender,Key.Age as Age,Count() as value)");

我被限制使用动态 linq 核心,因为在我的实际应用程序中,性别和年龄字段由用户决定,因此它们的字段名称会在运行时更改。

你会怎么做?

解决方法

假设您的查询返回以下类的对象列表

public class Data {
 public string Gender { get; set;}
 public int Age { get; set;}
 public int Value { get; set;}
}
  Data results = //query result

  var resultsV2 = results.GroupBy(r => r.Gender);
      
  var list = new List<IDictionary<string,object>>();

  foreach(var g in resultsV2)
  {
    IDictionary<string,object> obj = new ExpandoObject();

    var data = g.Select(x => x);
    obj["Gender"] = $"{g.Key}";
        
    foreach(var d in data)
    {
      var propName = $"{d.Age}";
      obj[propName] = $"{d.Value}";
    }

    list.Add(obj);

  }

  string jsonString = JsonConvert.SerializeObject(list);

Fiddler

输入:

new List<Data>
{
  new Data() { Gender = "Male",Age = 20,Value = 5 },new Data() { Gender = "Male",Age = 30,Value = 3 },new Data() { Gender = "Female",Value = 9 }
};

输出:

[{"Gender":"Male","20":"5","30":"3"},{"Gender":"Female","20":"9"}]
,

您可以在 LINQ 查询中利用 JSON.Net 类型。 JObject 接受 JProperty 的集合,JArray 接受 JObject 的集合。这些可以在一个 LINQ 查询中构建:

var table = new List<Person>{
        new Person(30,"M"),new Person(30,new Person(20,new Person(40,"V"),new Person(50,"V")
    };
    
    var data = 
        from p1 in table
        group p1 by p1.Gender into genderGrp  
        // Build our JObject
        select new JObject( 
            new JProperty( "Gender",genderGrp.Key)
            // and the rest of proprties will the collection of Age,(  from p2 in genderGrp            // over the gender
                 group p2 by p2.Age into ageGrp
                 select new JProperty(
                     ageGrp.Key.ToString()  // needs to be a string,ageGrp.Count()))       // aggregate count
       );
             
    var jtoken = new JArray(data);  // the collection of JObjects goes in the JArray
    Console.WriteLine(jtoken.ToString());

结果将是:

[
  {
    "Gender": "M","30": 3,"20": 1,"40": 1
  },{
    "Gender": "V","30": 1,"50": 2
  }
]