【问题标题】:Recursive Hierarchical Parent child递归分层父子
【发布时间】:2013-08-03 06:35:00
【问题描述】:

我有一组来自数据库的项目集合,其值为 parentid 或为空。

这是我的班级设计:

public class Item
{
public int id{get;set;}
public string Name{get;set;}
public int? ParentId{get;set;}
public List<Item> SubItems{get;set;}
}

我想从集合中构建项目的层次结构。假设一个集合是 100 个项目,我需要从中构建基于 ParentId 映射的结构。

我试过这个帖子Recursive Hierarchical Joins in C# and LINQ 但如果 ParentId 为空,它会给我一个错误。

也试过Build tree type list by recursively checking parent-child relationship C#,但这个解决方案对我也不起作用。

我如何做到这一点?

【问题讨论】:

    标签: c# .net algorithm linq


    【解决方案1】:

    您可以使用这种方法:

    1. 从数据库中获取所有项目(不填写子项目)。
    2. 构建一个包含父 ID 和具有该父 ID 的项目的 Lookup&lt;int?,Item&gt;
    3. 遍历项目并使用查找将每个项目与子项目相关联。

    代码:

    var items = // get from the database... (e.g. as a list)
    var lookup = items.ToLookup(x => x.ParentId);
    foreach (var item in items)
        item.SubItems = lookup[item.Id].ToList();
    

    正如 @EamonNerbonne 在下面评论的,如果需要,您也可以获取根元素:

    var roots = lookup[null].ToList();
    

    【讨论】:

    • 不需要那个Where 子句;如果你省略它,你可以做var roots = items[null].ToArray();
    • @EamonNerbonne 没错,Lookup&lt;&gt; 确实允许空键。
    【解决方案2】:

    使用这个Node class,您可以简单地做到这一点:

    var flatListOfItems = GetItemsFromDatabase();
    var rootNodes =Node<Item>.CreateTree(flatListOfItems, i => i.id, i => i.ParentId);
    

    您的项目不再需要子项目,因为 Node 类有一个 children 和一个 descendants 属性。 (还有祖先、兄弟姐妹、等级等)。

    CreateTree 方法产生 1 个或多个根节点。如果你确定总是有 1 个 rootnode,你可以通过 rootNodes.Single() 来获取 root。

    【讨论】:

    • 当您说 GetItemsFromDatabase() 时,您的意思是从数据库中获取所有记录吗?换句话说,运行“Select * from tableX”查询?除此之外,正如您所知,EF 也带来了所有的兄弟姐妹和祖先。在我看来,这是一个过度杀戮。同样适用于 Eren Ersönmez 的回复。
    • @KosalaW 在这个场景中,有 3 个字段的 100 个项目(子项目不存储在数据库中)。这不会占用太多时间和资源。在大多数情况下,很难在数据库中更快地做到这一点。在某些情况下,您需要另一种方法。
    【解决方案3】:

    您真的需要子项目的设置器吗?在 SQL Server 上运行 Select* 查询时,还要注意性能问题。

      public List<Item> SubItems{
      get
      {
       try{
            var validParents = db.items.Where(x=>x.ParentId!=null && x.ParentId.Equals(Id)); //db is your dbcontext
            if(validParents !=null)
            {
               return validParents.ToList(); 
            }else
            {
             return null;
            } 
            catch(Exception)
            {
              return null;
            }
       }
    

    (注意:考虑将其添加到您的部分实体类中。永远不要将您的实体命名为“Item”:)。Item 是保留字。 )

    【讨论】:

      猜你喜欢
      • 2021-07-04
      • 1970-01-01
      • 1970-01-01
      • 2015-01-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-19
      • 2021-11-27
      相关资源
      最近更新 更多