上篇介紹左右值編碼存儲,本文示範如何將按 LID ASC 讀出的扁平資料,在記憶體中重建樹形物件並遞歸輸出 HTML `
Tree(深度)欄位控制父子關係,純記憶體操作效能極高。
public class ZoneList
{
private readonly ZoneList _parent;
private readonly List<ZoneList> _children = new List<ZoneList>();
private readonly ZoneItem _value;
public ZoneList Parent => _parent;
public List<ZoneList> Children => _children;
public ZoneItem Value => _value;
public ZoneList Root
{
get
{
var cur = this;
while (cur.Parent != null) cur = cur.Parent;
return cur;
}
}
public ZoneList() { } // 根節點用
public ZoneList(ZoneItem value, ZoneList parent)
{
_value = value; _parent = parent;
}
public ZoneList AddChild(ZoneItem value)
{
var node = new ZoneList(value, this);
_children.Add(node);
return node;
}
}
public class ZoneItem
{
public int ID { get; set; }
public int Tree { get; set; }
public string Name { get; set; }
}
public ZoneList Select()
{
var root = new ZoneList(); // 虛擬根
var current = root;
int prevDepth = 0;
using (var reader = SiteSQL.ExecuteReader("ZoneSelect")) // SELECT ID, Tree, Name ORDER BY LID
{
while (reader.Read())
{
var item = new ZoneItem
{
ID = reader.GetInt32(0),
Tree = reader.GetInt32(1),
Name = reader.GetString(2)
};
// 根據深度差回溯父節點
int depthDiff = prevDepth - item.Tree;
for (int i = 0; i <= depthDiff; i++)
current = current.Parent;
current = current.AddChild(item);
prevDepth = item.Tree;
}
}
return root.Root; // 回傳真正根節點
}
private void ZoneOutWrite(ZoneList node)
{
foreach (var child in node.Children)
{
Response.Write(string.Format("- {1}",
child.Value.ID, child.Value.Name));
if (child.Children.Count > 0)
{
Response.Write("
");
ZoneOutWrite(child);
Response.Write("
");
}
Response.Write(" ");
}
}
// 頁面調用
var tree = Select();
Response.Write("");
ZoneOutWrite(tree);
Response.Write("
");
depthDiff = prevDepth - currentDepth 為正時表示回到祖先層級,循環 current = current.Parent 即可正確定位父節點。IsExpanded、IconUrl 等屬性支援前端樹形元件(如 jsTree、zTree)。