分层数据& LINQ - 最佳实践

时间:2012-11-08 15:30:12

标签: asp.net-mvc linq entity-framework linq-to-sql

想象一下当你有一个包含用户的表的情况时,我们的用户就有了一个层次结构。

[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; }

将样本数据放在那里:

UserId UserParentId用户名

  • 1 | null |老板
  • 2 | 1 |经理戴安娜
  • 3 | 2 |工人山姆
  • 4 | 2 |工人鲍勃
  • 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 UserId

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

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

关于如何在LINQ中实现这一点的任何想法和提示,考虑到可能有数千名员工和数千把铲子,并且不知道萧条等级的深度。

寻求帮助。

1 个答案:

答案 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();