Динамічні параметри для GroupBy Linq

21

Програмування Asp.net
Попередній

Наступний

Linq – це відмінна технологія для управління даними.

Однією з його особливостей є групування. Багато людей розуміють угруповання, як вона визначена в Sql. Linq здійснює угруповання цілком точно так само. Давайте дізнаємося цей синтаксис і як зробити послідовну угруповання простіше.

Припустимо, що є колекція замовників: «клієнт». Ви повинні використовувати GroupBy, щоб визначити групи серед ваших даних.

var q = from c in db.Customers
group c by c.Country;

В результаті ми отримаємо перерахування IGrouping. Він просто додати кілька речей:

– Ключ групи (країна в нашому прикладі).
– Елементи, згрупованих цим загальним ключем.

У більшості випадків ми використовуємо групи для отримання сум чи кількості значень.

var q =
from g in
(from c in db.Customers
group c by c.Country)
select new { g.Key, Count = g.Count() };

Щоб спростити цей синтаксис, ви можете використовувати ключове слово “into”

var q =
from c in db.Customers
group c by c.Country into g
select new { g.Key, Count = g.Count() };

Тепер давайте спробуємо створити під-групи всередині цього запиту. Мета проста: я хотів отримати групу клієнтів по країнам, а потім по містам всередині кожної групи.
Ми можемо записати це “вручну”:

var q =
from c in db.Customers
group c by c.Country into g
select new {
g.Key,
Count = g.Count(),
SubGroups = from c in g
group c by c.City into g2
select g2};

В результаті отримуємо дерево елементів, згрупованих у першому рівні по країні, а потім кожна група-країна містить підгрупи міст.

Цього код буде ставати все менш і менш читабельним, коли кількість груп під зростатиме. Я хотів зробити цей сценарій більш простим і більш загальним. Ось ідея.

Спочатку створимо клас який буде повертати наш запит. Клас потрібен для точного визначення групи, його можна повернути із методу. І метод в підсумку буде рекурсивний.

public class GroupResult
{
public object Key { get; set; }
public int Count { get; set; }
public IEnumerable Items { get; set; }
public IEnumerable SubGroups { get; set; }
public override string ToString()
{ return string.Format(“{0} ({1})”, Key, Count); }
}

Добре, тепер давайте напишемо головну роботу. Метод GroupByMany розширює IEnumerable , так само як і GroupBy, але ви можете додати невизначене число групових селекторів (params Func TKey> [] groupSelectors).
Якщо число групових селекторів дорівнює нулю, то метод повертає null. Це необхідно також для зупинки рекурсії у випадку декількох селекторів.

public static class GroupEnumerableExtensions
{
public static IEnumerable GroupByMany(
this IEnumerable elements,
params Func[] groupSelectors)
{
if (groupSelectors.Length > 0)
{
var selector = groupSelectors.First();
var nextSelectors = groupSelectors.Skip(1).ToArray();
return
elements.GroupBy(selector).Select(
g => new GroupResult
{
Key = g.Key,
Count = g.Count(),
Items = g,
SubGroups = g.GroupByMany(nextSelectors)
});
}
else
return null;
}
}

Приклад роботи:

var result = customers.GroupByMany(c => c.Country, c => c.City);