动态LINQ子查询 [英] Dynamic LINQ Sub Query
问题描述
我有要动态生成的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):
-
按照此答案在
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
...
}
将Select
,GroupBy
,ToList
添加到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屋!