С помощта на 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);
}
}
Ако приемем, че дефинирате свойство на Pages в PageInfo като:
public partial class PageInfo{
public List<PageInfo> Pages{get;set;}
}
Обработката за получаването му в йерархия се извършва от страна на уеб приложението, което избягва допълнително натоварване на sql сървъра. Също така имайте предвид, че този тип информация е перфектен кандидат за кеширане.
Можете да направите рендирането, както спомена Rex. Като алтернатива можете да разширите малко тази реализация и да я накарате да поддържа йерархичните интерфейси и да използва asp.net контроли.
Актуализация 1: За варианта на изобразяване, който поискахте в коментар, можете:
var sb = new System.IO.StringWriter();
var writer = new HtmlTextWriter(sb);
// rex's rendering code
var html = sb.ToString();