2010-01-07 83 views
1

我有一种方法从数据库中检索一组记录。Linq构建分层列表

我将这些数据映射到一个业务对象 - 让我们称之为业务对象ProcessModel。 ProcessModel中的一个属性是一个名为ProcessChildren的列表。该属性是List。

因此,数据通过各种字段/属性进行链接。在层次结构列表顶部有一个对象,然后该对象在其ProcessChildren属性中具有多个对象,这些对象在其ProcessChildren属性中具有多个对象等。

无论如何,我写了相当多的代码来遍历返回数据集,然后构建分层列表,然后将其绑定到Silverlight中的TreeView。

我会非常感激,如果有人可以提供一个更清洁,更简单的方法来做到这一点,无论是使用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; 
            } 
           } 
          } 
         } 
        } 
       } 
      } 
     } 

回答

1

This related post可能帮助....

更新:这里的支持下面的评论代码...你需要编辑来支持自己的类。

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 
     } 
    } 
} 
+0

谢谢 - 但我不确定这是否能解决我的问题。之所以这么说,是因为那个人似乎在做我以前看过的很多东西 - 哪里有顶级,哪些是子级别的东西。就我而言,它是动态的,基于列表中的每个项目。一个项目可能有一个孩子,那么这个孩子可能有三个孩子,那么其中一个孩子可能有一个孩子等等... – Chris 2010-01-07 19:03:20

+0

好吧,我会认为你可以把一些东西放在循环中...像(伪代码):while procs.Any(p => p.SubProcs == null){foreach其中proc.SubProcs = null {proc.SubProcs = <解析原始列表以填充subprocs>列表}} - 这将递归地查找所有.. 。注意,assigment应该为叶子进程返回一个空的列表,以避免无限循环。 – 2010-01-07 19:09:15

+0

顺便说一句,我没有在Process上看到'ParentId'属性...那里是什么?如果我能弄明白,那么我可以发布实际的工作代码 – 2010-01-07 19:18:25

1

我想这个答案是有点晚了,但在这里不用。

尝试使用.LookUp(...)扩展方法和递归lambda表达式:

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关系隐式定义了级别。