我对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;
}
是否会接受这种匿名类型)
答案 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")