動的に生成したいLINQクエリがあります。
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()
};
最終的な目標は、ネストされたクエリに制限のないフィールドの任意の組み合わせでデータを動的にグループ化できるようにすることです。
私は最初のレベルまで到達できますが、ネストされたサブクエリに苦労しています:
string field1 = "Field1";
string field2 = "Field2";
var groupDataD =
data.
GroupBy(field1, "it").
Select("new ( it.Key, it.Count() as Count )");
これは連鎖動的LINQで可能ですか?またはこれを達成するためのより良い方法はありますか?
以下は機能するはずです(個人的には、そのようなコードの使用は避けたいと思います)。
この回答に従って、 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
ます 。
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")
...
}
最後に、クエリは次のようになります。
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"
は、親クエリとサブクエリで使用される場合、異なるインスタンスを保持する"it"
注意してください。私はを利用しようとした"outerIt"
(しかし、多分あなたは?多分成功するだろう。この混同を克服するために、残念ながら成功なし1 、 2役立つだろう)
将来の参考のための簡単な例:
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}");
}
}
}