2012-11-08 43 views
1

想象一下当您有一个带有用户表的用户时,我们的用户具有分层结构的情况。分层数据和LINQ - 最佳实践

[Key] 
public virtual int UserId { get; set; } 

public virtual UserProfile UserParent { get; set; } 
public virtual int? UserParentId { get; set; } 
public virtual String UserName { get; set; } 

放置在那里的样本数据:

用户ID UserParentId用户名

  • 1 | null |老板
  • 2 | 1 |经理戴安娜
  • 3 | 2 |工人山姆
  • 4 | 2 |工人Bob
  • 5 | 1 |黄经理
  • 6 | 5 |工人路

为每个用户分配一个铲:P

[Key] 
public virtual int ShovelId { get; set; } 

public virtual string ShovelSerialNumber { get; set; } 
public virtual int UserId { get; set; } 

放置在那里的样本数据:

ShovelId ShovelSerialNumbe用户ID

  • 1 | 12345BK | 3
  • 2 | 99999ZK | 4
  • 3 | 88888KP | 6

所有这些的目的是获取挖土机的序列号,在用户表上进行分层查询。老板会看到所有的铲子,但只有铲子管理下属员工。

关于如何在LINQ中实现这一点的任何想法和提示,考虑到可能有数千名员工和数千个铁锹,并且不知道抑郁症等级的深度。

Thx寻求帮助。

+0

您已经使用ORM标签,提示有涉及到数据库,在这种情况下,所有分层的东西都应该在数据库中完成。 LINQ无法真正表达分层查询。 – AakashM

+0

我知道,但这种情况会重复,所以我问。 –

回答

2

第1步:使用您的ORM加载记录(例如,linqToSql)。使用正确的设置,记录之间的所有关系都会自动生成。

第2步:使用正常码周游内存树:

public static IEnumerable<T> WalkTreeBreadthFirst<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childFunction) 
    { 
     // http://en.wikipedia.org/wiki/Breadth-first_search 
     HashSet<T> seenIt = new HashSet<T>(); 
     Queue<T> toVisit = new Queue<T>(); 

     foreach (T item in source) 
     { 
      toVisit.Enqueue(item); 
     } 

     while (toVisit.Any()) 
     { 
      T item = toVisit.Dequeue(); 
      if (!seenIt.Contains(item)) 
      { 
       seenIt.Add(item); 
       foreach (T child in childFunction(item)) 
       { 
        toVisit.Enqueue(child); 
       } 
       yield return item; 
      } 
     } 
    } 

    public static IEnumerable<T> WalkTreeDepthFirst<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> childFunction) 
    { 
     // http://en.wikipedia.org/wiki/Depth-first_search 
     HashSet<T> seenIt = new HashSet<T>(); 
     Stack<T> toVisit = new Stack<T>(); 

     foreach (T item in source.Reverse()) 
     { 
      toVisit.Push(item); 
     } 

     while (toVisit.Any()) 
     { 
      T item = toVisit.Pop(); 
      if (!seenIt.Contains(item)) 
      { 
       seenIt.Add(item); 
       foreach (T child in childFunction(item).Reverse()) 
       { 
        toVisit.Push(child); 
       } 
       yield return item; 
      } 
     } 
    } 

例如:

List<Person> bosses = tree.GetBossesByID(3, 4, 5); 
List<Shovel> shovels = bosses 
    .WalkTreeBreadthFirst(x => x.Subordinates) 
    .Select(p => p.Shovel) 
    .ToList(); 
+0

我想我还是不明白这个概念,或许是一个更清晰的例子? –