我有tableId,parentPageId,title columns的表。
有没有办法使用asp.net,cte,存储过程,UDF返回无序的嵌套列表......什么?
表格如下:
PageID ParentId Title
1 null Home
2 null Products
3 null Services
4 2 Category 1
5 2 Category 2
6 5 Subcategory 1
7 5 SubCategory 2
8 6 Third Level Category 1
...
结果应如下所示:
Home
Products
Category 1
SubCategory 1
Third Level Category 1
SubCategory 2
Category 2
Services
理想情况下,列表也应包含<a>
标记,但如果我找到创建<ul>
列表的方法,我希望自己可以添加它。
编辑1:我认为已经有了解决方案,但似乎没有。我希望尽可能保持简单并且不惜任何代价逃避使用ASP.NET菜单,因为它默认使用表。然后我必须使用CSS Adapters等。
即使我决定沿着“ASP.NET菜单”路线走,我也只能找到这种方法:http://aspalliance.com/822使用DataAdapter和DataSet :(
更现代或更有效的方式?
答案 0 :(得分:5)
使用linq2sql你可以这样做:
List<PageInfo> GetHierarchicalPages()
{
var pages = myContext.PageInfos.ToList();
var parentPages = pages.Where(p=>p.ParentId == null).ToList();
foreach(var page in parentPages)
{
BuildTree(
page,
p=> p.Pages = pages.Where(child=>p.pageId == child.ParentId).ToList()
);
}
}
void BuildTree<T>(T parent, Func<T,List<T>> setAndGetChildrenFunc)
{
foreach(var child in setAndGetChildrenFunc(parent))
{
BuildTree(child, setAndGetChildrenFunc);
}
}
假设您在PageInfo中定义Pages属性,如:
public partial class PageInfo{
public List<PageInfo> Pages{get;set;}
}
在Web应用程序端进行在层次结构上获取它的处理,这避免了sql server上的额外负载。另请注意,此类信息是缓存的理想选择。
您可以像雷克斯提到的那样进行渲染。或者,您可以在此实现上进行一些扩展,并使其支持层次结构接口并使用asp.net控件。
更新1:对于您在评论中询问的渲染变体,您可以:
var sb = new System.IO.StringWriter();
var writer = new HtmlTextWriter(sb);
// rex's rendering code
var html = sb.ToString();
答案 1 :(得分:2)
最佳做法是使用IHierarchyData和IHierarchalEnumerable以及DataBind执行此操作,以继承自HierarchalDataBoundControl的自定义控件(这是TreeView等控件的基础)
但是,让我们尝试在c#中使用快速而肮脏,不是特别有效的简单示例:
//class to hold our object graph in memory
//this is only a good idea if you have a small number of items
//(less than a few thousand)
//if so, this is a very flexible and reusable way to represent your tree
public class Page
{
public string Title {get;set;}
public int ID {get;set;}
public Collection<Page> Pages = new Collection<Page>();
public Page FindPage(int id)
{
return FindPage(this, id);
}
private Page FindPage(Page page, int id)
{
if(page.ID == id)
{
return page;
}
Page returnPage = null;
foreach(Page child in page.Pages)
{
returnPage = child.FindPage(id);
if(returnPage != null)
{
break;
}
}
return returnPage;
}
}
//construct our object graph
DataTable data = SelectAllDataFromTable_OrderedByParentIDAscending();
List<Page> topPages = new List<Page>();
foreach(DataRow row in data.Rows)
{
Page page = new Page();
page.Title = (string)row["Title"];
page.ID = (int)row["PageID"];
if(row["ParentID"] == null)
{
topPages.Add(page);
}
else
{
int parentID = (int)row["ParentID"];
foreach(Page topPage in topPages)
{
Page parentPage = topPage.FindPage(parentID);
if(parentPage != null)
{
parentPage.Pages.Add(page);
break;
}
}
}
}
//render to page
public override void Render(HtmlTextWriter writer)
{
writer.WriteFullBeginTag("ul");
foreach(Page child in topPages)
{
RenderPage(writer, child);
}
writer.WriteEndTag("ul");
}
private void RenderPage(HtmlTextWriter writer, Page page)
{
writer.WriteFullBeginTag("li");
writer.WriteBeginTag("a");
writer.WriteAttribute("href", "url");
writer.Write(HtmlTextWriter.TagRightChar);
writer.Write(page.Title);
writer.WriteEndTag("a");
if(page.Pages.Count > 0)
{
writer.WriteFullBeginTag("ul");
foreach(Page child in page.Pages)
{
RenderPage(writer, child);
}
writer.WriteEndTag("ul");
}
writer.WriteEndTag("li");
}
答案 2 :(得分:0)
这应该让你开始。
with x (pageID, title)
as (
select cast(title as varchar(100)),pageID
from pages
where parentID is null
union all
select cast(x.title||' - '||e.title as varchar(100)),
e.pageID
from pages e, x
where e.parentID = x.pageID
)
select title as title_tree
from x
order by 1
输出:
TITLE_TREE
Home
Products
Services
Products - Category 1
Products - Category 2
Products - Category 2 - Subcategory 1
Products - Category 2 - Subcategory 1 - Third Level Category 1
Products - Category 2 - Subcategory 2
答案 3 :(得分:0)
您是否考虑过使用SELECT从SQL Server获取XML输出... FOR XML EXPLICIT?您的数据似乎完全符合要求。
举个例子:
http://www.eggheadcafe.com/articles/20030804.asp
如果你想追求,我可以通过一个例子。
答案 4 :(得分:0)
RexM - 首先我必须声明我是一名前端开发人员,因此甚至无法触及您的编码C#的技能和知识。但是 - 我确实使用Page对象实现了您的解决方案并遇到了问题。是的,对不起,在这种情况下,我是一个“请发送给我的代码”水蛭,但是从不遗憾,认为详细说明“虫子”非常重要。
我正在构建一个使用嵌套UL显示菜单项的网站,并允许用户根据需要重新排序菜单。
我的菜单包含以下数据字段:pageID,parentID,pageOrder,pageTitle
页面顺序是指页面在节点中的显示顺序。
所以我对SelectAllDataFromTable_OrderedByParentIDAscending();
的查询是:
SELECT * FROM [pages] ORDER BY [parentID] ASC, [pageOrder] ASC
然后我使用jsTree使菜单项可拖动和可拖放。
我重新订购了几页并发现了一个错误:
说我的结构是这样的:
home
cars
usa
muscle cars
suvs
europe
colours
directions
vertical
horizontal
up
down
如果我将“汽车”(及其所有孩子)移到“向下”里面,“汽车”的孩子就不再显示在菜单中了。那就是“虫子”。
我已经检查了数据库并且 parentID 和 pageOrder 在“cars”下都是正确的,我也尝试更改我的SQL查询,从头开始,进行各种测试直接在DB上(以上所有关闭jsTree所以我可以看到基本的嵌套UL) - 但没有成功。
只是想知道,正如我看到其他论坛指向此页面的解决方案将分层sql数据转换为嵌套的UL,可能值得有人研究它。
由于我的整个网站都基于Javascript的使用,我现在已经实现了一个Jquery.ajax解决方案(非常糟糕的评论,在my site这里)来构建嵌套的UL,但正如我所说,只是标记为潜在的问题。
非常感谢我自己找到解决方案的一脚开始!