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