LINQ GroupBy具有多个动态复杂参数

时间:2019-09-06 09:48:50

标签: vb.net linq dynamic

我对LINQ并不陌生,在过去的几天里,我一直在努力实现以下目标。
我需要对一组相当复杂的对象进行分组(以及查询,然后再做一些聚合工作)。
问题是我需要按单个或多个参数进行查询/分组,而这些参数的名称在设计时是未知的。理想情况下,我想为数组提供一个代表参数名称的字符串,并完成分组。
另外,有问题的参数嵌套在要分组的对象所包含的集合中。
这是一个示例:

收藏夹中的对象

Class qItem
    Property qName As String
    Property qStuff As String
    Property qList As List(Of qTag)
End Class
Class qTag
    Property Tag As String
    Property Value As String
End Class

主要收藏

Dim qResult As New List(Of qItem)

该集合已填充

qResult.Add(New qItem With {.qName = "N1", .qStuff = "S1", .qList = New List(Of qTag) From {
                                        New qTag With {.Tag = "T1", .Value = "VAA"},
                                        New qTag With {.Tag = "NAME", .Value = "V2"}}})
qResult.Add(New qItem With {.qName = "N1", .qStuff = "S3", .qList = New List(Of qTag) From {
                                        New qTag With {.Tag = "T1", .Value = "V1"},
                                        New qTag With {.Tag = "NAME", .Value = "V2"}}})
qResult.Add(New qItem With {.qName = "N2", .qStuff = "S1", .qList = New List(Of qTag) From {
                                        New qTag With {.Tag = "T1", .Value = "V1"},
                                        New qTag With {.Tag = "NAME", .Value = "VZZ"}}})
qResult.Add(New qItem With {.qName = "N2", .qStuff = "S3", .qList = New List(Of qTag) From {
                                        New qTag With {.Tag = "T1", .Value = "V1"},
                                        New qTag With {.Tag = "NAME", .Value = "VZZ"}}})
qResult.Add(New qItem With {.qName = "N2", .qStuff = "S1", .qList = New List(Of qTag) From {
                                        New qTag With {.Tag = "T1", .Value = "VAA"},
                                        New qTag With {.Tag = "NAME", .Value = "VZZ"}}})

现在。我想通过qResult包含的集合中Value对象的qTag属性的qItem属性对Tag中的对象进行分组。分组应通过qTag对象的Dim R = From q In qResult Group By q.qList.FirstOrDefault(Function(x) x.Tag = "NAME")?.Value Into Group 属性来完成。

如果我只需要按一个参数分组,则可以执行以下操作:

"NAME"

"NAME"是我可以用来进行分组的值。
如果我需要按多个参数分组(例如"T1" Dim Rt = From q In qResult Group By MyGrouping = New With { Key .g1 = q.qList.FirstOrDefault(Function(x) x.Tag = "NAME")?.Value, Key .g2 = q.qList.FirstOrDefault(Function(x) x.Tag = "T1")?.Value } Into Group ),我就知道可以做到这一点:

qitem

但是现在,我不再能够动态提供分组信息。为此,我将需要以某种方式生成具有动态属性的匿名类型。

之后,我按照here所述研究了动态LINQ
这样,我学会了可以像这样进行分组。例如,如果我需要按Dim Rt1 = qResult.GroupBy("new (qName, qStuff)", "it")

的简单属性进行分组
Dim GroupingParams As String() = {"qName", "qStuff"}
Dim Rt2 = qResult.GroupBy("new (" & String.Join(",", GroupingParams) & ")", "it")

这有效,我也可以将信息作为数组传递

qitem

但这仅适用于Value的属性。我最初的目标是按照qTag中包含的集合中qItem中的"new (qName, qStuff)"属性对项目进行分组。
看来,动态LINQ在Dim Rt3 = qResult.GroupBy("qList.FirstOrDefault(Function(x) x.Tag = ""NAME"")?.Value,", "it") 处进行了某种评估。虽然,我找不到可以评估或无法评估的全面描述。所以这不起作用

Group By

是否可以将其传递给Dynamic Linq?
还是应该开始研究反射或动态匿名类型? (不过,我不确定常规LINQ int f(int n) { int i,j,k,p,r=0; k=sqrt(n); p=n/2; for (i=2; i<=p; i++) for(j=2; j<=k; j++) if(i*j==n) r++; return r; } 是否会接受这种匿名类型)

1 个答案:

答案 0 :(得分:1)

是的,您不使用lambda Function(x)构造,它是隐式的:

Dim Rt3 = qResult.AsQueryable.GroupBy("iif(qList.FirstOrDefault(Tag = ""NAME"") == null, null, qList.FirstOrDefault(Tag = ""NAME"").Value)", "it")

注意:您不能在Expression树中使用空值传播运算符(因为C#严重忽略了更新Expression)并且np()不够灵活,无法处理此问题,因此您必须手动扩展测试,并运行两次FirstOrDefault :(如果您可以改用First,那就很简单:

Dim Rt3 = qResult.AsQueryable.GroupBy("qList.First(Tag = ""NAME"").Value", "it")

要按匿名对象分组,必须确保没有重复的字段名称,因此请使用as来命名每个字段:

Dim Rt3 = qResult.AsQueryable.GroupBy("new (qList.FirstOrDefault(Tag = ""T1"").Value as T1,qList.FirstOrDefault(Tag = ""NAME"").Value as Name)", "it")