如何使用C#递归创建对象菜单层次结构?

时间:2014-05-02 08:34:35

标签: c# asp.net .net

对于一个项目,我想使用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

4 个答案:

答案 0 :(得分: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);
   }
}

答案 1 :(得分:1)

对于使用Dictionary的更大数据集,可以提供更好的性能。 它只需要遍历所有可能的子代,并且字典中父代的查找接近于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);
}

答案 2 :(得分:0)

在返回pageItems之前,迭代每个项目并使用将其作为父项的项目填充Childs集合...

using System.Linq;
// ...

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

return pageItems;

答案 3 :(得分: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