Рекурсивная группировка Linq - PullRequest
4 голосов
/ 05 марта 2011

Сценарий: У меня есть таблица базы данных, которая хранит иерархию отношения многих ко многим другой таблицы. Элемент может иметь несколько дочерних элементов, а также может иметь более одного родителя.

Items    
------ 
ItemID (key)

Hierarchy
---------
MemberID (key)
ParentItemID (fk)
ChildItemID (fk)

Пример иерархии:

Level1  Level2  Level3
X       A       A1
                A2
        B       B1
                X1
Y       C

Я хотел бы сгруппировать все дочерние узлы по каждому родительскому узлу в иерархии.

Parent  Child
X       A1
        A2
        B1
        X1
A       A1
        A2
B       B1
        X1
Y       C
  • Обратите внимание, что в столбце «Родитель» нет конечных узлов, и как столбец «Дочерние» только содержит узлы листа.
  • В идеале я хотел бы, чтобы результаты были в форме IEnumerable <<code>IGrouping< Item, Item >> , где ключом является Parent, а все элементы группы - Children.
  • В идеале я хотел бы получить решение, которое провайдер сущностей может преобразовать в T-SQL, но если это невозможно, то мне нужно сводить к минимуму повторные поездки.
  • Я намерен суммировать значения, которые существуют в другой таблице, объединенной на конечных узлах.

Ответы [ 2 ]

1 голос
/ 07 марта 2011

Поскольку вы всегда будете возвращать ВСЕ элементы в таблице, почему бы просто не сделать рекурсивный метод, который получает все дочерние элементы для родителя, а затем использовать его для элементов в памяти:

затем:

var items = 
    from item in Items.ToList()
    group new 
    {
        item.itemID,
        item.GetAllChildren()
    } by item.itemID;

Извините за любые синтаксические ошибки ...

0 голосов
/ 06 марта 2011

Что ж, если иерархия строго состоит из 2 уровней, вы всегда можете объединить их и позволить LINQ разобраться с SQL-запросом (в конечном итоге это будет одна поездка, хотя нужно посмотреть, насколько быстро она будет выполняться на вашем объеме данных):

var hlist = from h in Hierarchies
            select new {h.Parent, h.Child};

var slist = from h in Hierarchies
            join h2 in hlist on h.Parent equals h2.Child
            select new {h2.Parent, h.Child};

hlist = hlist.Union(slist);

Это дает вам плоский список IEnumerable<{Item, Item}>, поэтому, если вы хотите сгруппировать их, просто следуйте:

var glist = from pc in hlist.AsEnumerable()
            group pc.Child by pc.Parent into g
            select new { Parent = g.Key, Children = g };

Я использовал AsEnumerable() здесь, когда мы достигли возможности поставщика LINQ SQL при попытке сгруппировать Союз. Если вы попробуете это против IQueryable, он запустит базовый Союз для подходящих родителей, а затем совершите круговую поездку для каждого родителя (чего вы и хотите избежать). Независимо от того, нормально ли вам использовать регулярное LINQ для группировки, зависит тот же объем данных, который в любом случае должен был бы пройти по каналу.

РЕДАКТИРОВАТЬ: В качестве альтернативы вы можете создать представление, связывающее родителя со всеми его дочерними элементами, и использовать это представление в качестве основы для связывания элементов. Теоретически это должно позволить вам / L2S сгруппировать его за одну поездку.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...