Linq для построения иерархического списка - PullRequest
1 голос
/ 07 января 2010

У меня есть метод, который извлекает набор записей из базы данных.

Я сопоставляю эти данные с бизнес-объектом - давайте назовем бизнес-объект ProcessModel. Одним из свойств в ProcessModel является список, который называется ProcessChildren. Свойство List.

Итак, данные связаны различными полями / свойствами. В верхней части иерархического списка находится один объект, затем этот объект имеет несколько объектов в своем свойстве ProcessChildren, эти объекты имеют несколько объектов в своих свойствах ProcessChildren и т. Д.

Во всяком случае, я написал довольно много кода для итерации по возвращенному набору данных и создал иерархический список, который я затем связал с TreeView в Silverlight.

Я был бы очень признателен, если бы кто-то мог предоставить мне гораздо более простой и понятный способ сделать это, либо с помощью linq, либо с помощью linq, либо с помощью другого подхода с помощью метода расширения.

Я включил код, который сейчас использую, чтобы, надеюсь, лучше проиллюстрировать, чего я пытаюсь достичь.

var processes = new List<Process>();

        var rootLevelProcesses = new List<Process>();

        var allProcesses = new List<Process>();

        foreach (Process process in e.Results)
        {
            process.ProcessChildren = new List<Process>();

            if (process.ParentId > 0 || (process.ParentId == 0 && process.EntityId == 1))
            {
                allProcesses.Add(process);
            }
        }

        var rootProcess =
                    (from parent in e.Results
                     where parent.EntityType == 1 && parent.ContainerLevel <= 1
                     select parent).FirstOrDefault();

        processes.Add(rootProcess);

        var level2Processes = (from parent in allProcesses
                               where parent.EntityType == 1 && parent.ContainerLevel == 2
                               select parent).ToList();

        foreach (Process process in level2Processes)
        {
            var level3Processes = (from parent in allProcesses
                                   where parent.EntityType == 1 && parent.ContainerLevel == 3
                                   select parent).ToList();

            process.ProcessChildren = level3Processes;
        }

        processes[0].ProcessChildren = level2Processes;

        foreach (Process process in processes)
        {
            if (process.ProcessChildren != null && process.ProcessChildren.Count > 0)
            {
                foreach (Process level1 in process.ProcessChildren)
                {
                    if (level1.EntityType == 1)
                    {
                        var children =
                        (from child in allProcesses
                         where child.ParentId == level1.EntityId
                         select child).ToList();

                        level1.ProcessChildren = children;

                        foreach (Process level2 in level1.ProcessChildren)
                        {
                            if (level2.EntityType == 1)
                            {
                                children =
                            (from child in allProcesses
                             where child.ParentId == level2.EntityId
                             select child).ToList();

                                level2.ProcessChildren = children;

                                foreach (Process level3 in level2.ProcessChildren)
                                {
                                    if (level3.EntityType == 1)
                                    {
                                        children =
                                    (from child in allProcesses
                                     where child.ParentId == level3.EntityId
                                     select child).ToList();

                                        level3.ProcessChildren = children;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }

Ответы [ 2 ]

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

Я думаю, что этот ответ немного запоздал, но здесь идет.

Попробуйте использовать метод расширения .LookUp(...) и рекурсивное лямбда-выражение:

var lookup = e.Results.ToLookup(x => x.ParentId);

Action<IEnumerable<Process>> addChildren = null;
addChildren = ps =>
{
    foreach (var p in ps)
    {
        p.ProcessChildren = lookup[p.EntityId].ToList();
        addChildren(p.ProcessChildren);
    }
};

var rootProcesses = e.Results.Where(x => x.ParentId == 0);

addChildren(rootProcesses);

Это хорошо работало с данными испытаний, которые я создал. Я не использовал свойство ContainerLevel, поскольку отношение ParentId неявно определяет уровень.

1 голос
/ 07 января 2010

Этот пост может помочь ....

Обновление : вот код в поддержку комментариев ниже ... Вам нужно будет отредактировать для поддержки ваших собственных классов.

public class Proc
{
    public System.Diagnostics.Process RealProc;
    public List<Proc> SubProcs = null;
}

void Main()
{
    var Processes = from p in System.Diagnostics.Process.GetProcesses() select new Proc { RealProc = p, SubProcs = null };
    while (Processes.Any(pr => pr.SubProcs == null))
    {
        foreach(Proc pr in Processes)
        {
            pr.RealProc.Id.Dump();
            pr.SubProcs = Processes.Where(prx => prx.RealProc.ParentId == pr.Id).ToList();  // doesn't work because no ParentId
        }
    }
}
...