2014-05-02 59 views
-1

对于一个项目,我想使用C#创建递归对象(菜单)层次结构。我从互联网上阅读并尝试了很多,但我无法快速修复它。 为了阐明我的问题,我创建了一个简单的数据库表。如何用C#创建一个对象菜单层次递归?

CREATE TABLE Page 
(
    Id INT NOT NULL PRIMARY KEY IDENTITY, 
    ParentId INT DEFAULT 0, 
    MenuTitle VARCHAR(255) NOT NULL 
) 

INSERT INTO Page (ParentId, MenuTitle) VALUES 
(0, 'Parent 1'), 
(1, 'Child 1'), 
(1, 'Child 2'), 
(3, 'ChildChild 1'), 
(3, 'ChildChild 2'), 
(3, 'ChildChild 3'), 
(0, 'Parent 2'), 
(0, 'Parent 3'), 
(0, 'Parent 4') 

*的ParentId 0是主导航项目

这是模型。

class PageItem 
{ 
    public int Id { get; set; } 
    public int ParentId { get; set; } 
    public string MenuText { get; set; } 
    List<PageItem> Childs { get; set; } 
} 

要从数据库加载数据,您可以使用此方法。

public List<PageItem> GetPageItems() 
     { 
      List<PageItem> pageItems = new List<PageItem>(); 
      SqlConnection conn = new SqlConnection(" * YOUR CONNECTIONSTRING *"); 
      SqlCommand cmd = new SqlCommand("SELECT Id, ParentId, MenuTitle FROM Page", conn); 
      conn.Open(); 
      SqlDataReader rdr = cmd.ExecuteReader(); 
      while (rdr.Read()) 
      { 
       pageItems.Add(new PageItem() 
       { 
        Id = Convert.ToInt32(rdr["Id"]), 
        ParentId = Convert.ToInt32(rdr["ParentId"]), 
        MenuText = rdr["MenuTitle"].ToString() 
       }); 
      } 
      rdr.Close(); 
      conn.Close(); 
      return pageItems; 
     } 

我希望模型递归填充,看起来像这样。

- Parent 1 
-- Child 1 
-- Child 2 
--- ChildChild 1 
--- ChildChild 2 
--- ChildChild 3 
- Parent 2 
- Parent 3 
- Parent 4 

有谁知道我怎么能意识到这一点?

非常感谢。

的Jordy

回答

1

更换你读的循环使用:

var allItems = new List<PageItem>(); 
while (rdr.Read()) 
{ 
    var item = new PageItem() 
       { 
        Id = Convert.ToInt32(rdr["Id"]), 
        ParentId = Convert.ToInt32(rdr["ParentId"]), 
        MenuText = rdr["MenuTitle"].ToString() 
       }); 
    allItems.Add(item); 
    var parent = allItems.Where(pi => pi.Id == item.ParentId).SingleOrDefault(); 
    if (parent == null) 
    { 
     pageItems.Add(item); 
    } 
    else 
    { 
     if (parent.Childs == null) 
     parent.Childs = new List<PageItem>(); 
     parent.Childs.Add(item); 
    } 
} 
+0

谢谢。最后一行给出了一个空引用异常。 – Jordy

+0

@Jordy现在修好 – decPL

+0

我看到7位家长,还有4位家长(见主要帖子)。对象中的3级缺失。我认为这个解决方案只适用于两个级别的深度,而可能是无限的。 – Jordy

0

之前返回pageItems,遍历每个项目填充Childs收集与它作为一个父项...

using System.Linq; 
// ... 

pageItems.ForEach(p => 
{ 
    p.Childs = pagesItems.Where(c => c.ParentId == p.Id).ToList(); 
}); 

return pageItems; 
0

你不需要任何代码。您可以使用common table expression像这样

;with cte as 
(
    select convert(varchar(20),'-') as caption, *, convert(varchar(10),id) as o 
    from Page 
    where ParentId=0 
    union all 
    select convert(varchar(20),caption + '-'), page.id, page.parentid, page.menutitle, convert(varchar(10),o + convert(varchar(10),page.id)) 
    from cte 
     inner join page on cte.Id = page.ParentId  
)  
select caption+' ' + MenuTitle from cte 
order by o 
+0

它必须在代码中,因为我想要一个通用的方法在C#中使用 - 这是更好的可读性。 – Jordy

+0

然后你应该说“我希望它比所需要的更复杂” – podiluska

1

对于使用字典的较大数据集会提供更好的性能。 它只需要遍历所有可能的子元素,并且字典中的父元素查找接近于O(1) 此代码依赖于数据库中正确清理过的值。

Dictionary<int, PageItem> Items = new Dictionary<int, PageItem>(); 
while (rdr.Read()) 
{ 
    var item = new PageItem() 
    { 
     Id = Convert.ToInt32(rdr["Id"]), 
     ParentId = Convert.ToInt32(rdr["ParentId"]), 
     MenuText = rdr["MenuTitle"].ToString(), 
     Childs = new List<PageItem>() 
    }; 
    Items[item.Id] = item; 
} 
foreach (var pair in Items) 
{ 
    PageItem item = pair.Value; 
    if (item.ParentId == 0) 
     continue; 

    Items[item.ParentId].Childs.Add(item); 
}