为指定的父母提供所有级别的子女和子女

时间:2014-03-20 09:38:12

标签: sql linq entity-framework

我有一个名为Groups的表。该表的结构是:

GroupID     1-------
GroupName          |
ParentID    *-------

现在我想为特定的父母找到所有的孩子和孙子。

我尝试过以下代码。但它只给了我一到二级的孩子:

List<string> groups = new List<string>();


var parent = (from g in db.Groups
              where g.GroupID == 1
              select g).FirstOrDefault();

var Children = (from x in db.Groups
                where x.ParentID == parent.GroupID
                select x);

groups.AddRange(Children.Select(x => x.GroupName));

foreach (Group children in Children)
{
    var grandChildren = (from x in db.Groups
                         where x.ParentID == children.GroupID
                         select x.GroupName);
        groups.AddRange(grandChildren);
}  


StringBuilder builder = new StringBuilder();

foreach (string str in groups)
{
    builder.Append(str.ToString()).AppendLine();
}

MessageBox.Show(builder.ToString());

2 个答案:

答案 0 :(得分:3)

您可以尝试递归地执行此操作:

IEnumerable<Group> GetAllChildren(Group parent) 
{
   var result = (from x in db.Groups
            where x.ParentID == parent.GroupID
            select x);
   foreach (Group child in result)
   {
      result.AddRange(GetAllChildren(child));
   }
   return res;
}

这只是一个例子,并没有检查循环引用。

答案 1 :(得分:1)

如果你不想do it in the database,这可能会更有效率,你可以做这样的事情。

注意,我创建了一个字典,以防止每一代都访问数据库。如果您只获得所有组的一小部分,或者如果代数很小,这可能是错误的方法。

如果重复此过程并且可以缓存组字典,则这将是有效的并且可以防止多次访问数据库。这个函数没有分配额外的内存来构建结果集,只是懒得走树。

IDictionary<int, Group> groups;
using(var db = new Context())
{
    groups = db.Groups.ToDictionary(g => g.GroupID, g => g)
}

var all = FlattenGroups(groups, new[] { groups[1] });

private IEnumerable<Group> FlattenGroups(
        IDictionary<int, Group> groups,
        IEnumerable<group> topSet)
{
    return topSet.SelectMany(group =>
        FlattenGroups(
                groups,
                groups[group.ParentID])
        .Concat(topSet));
}