首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

LINQ 實現無限級 TreeView 懶惰載入最佳實踐

     編輯:程式設計綜合問答

核心結論

不要嘗試一次性載入所有層級資料。TreeView 的正確做法是懶惰載入:使用者展開節點時,才向資料庫查詢該節點的直接子節點。

為什麼不用 SelectMany / GroupBy 一次載入?

  • 資料量不可控:幾萬筆資料會導致記憶體暴增、UI 凍結
  • 使用者通常只看前幾層,載入未展開分支是浪費
  • 遞迴查詢在資料庫端效率低(遞迴 CTE 或多次往返)

推薦架構:需求驅動載入

1. 資料庫設計

CREATE TABLE TreeNode (
    Id INT PRIMARY KEY,
    ParentId INT NULL,
    Name NVARCHAR(100),
    HasChildren BIT NOT NULL DEFAULT 0  -- 關鍵:標記是否有子節點
);

2. 後端 API 設計

// GET /api/nodes?parentId=123
public IActionResult GetChildren(int? parentId) {
    var nodes = _context.TreeNodes
        .Where(n => n.ParentId == parentId)
        .Select(n => new {
            n.Id,
            n.Name,
            n.HasChildren,  // 前端據此決定是否顯示展開箭頭
            children = new object[0]  // 懶惰載入時不回傳 children
        })
        .ToList();
    return Json(nodes);
}

3. 前端實現

// jQuery 範例
$('#tree').tree({
    url: '/api/nodes',
    method: 'get',
    animate: true,
    lines: true,
    onBeforeExpand: function(node) {
        if (!node.state || !node.state.loaded) {
            $('#tree').tree('options').url = '/api/nodes?parentId=' + node.id;
        }
    },
    onLoadSuccess: function(node, data) {
        if (node) node.state.loaded = true;
    }
});

若必須一次性載入(資料量極小)

使用 ToLookup 建立父子映射,遞迴構建樹:

var allNodes = db.TreeNodes.ToList();
var lookup = allNodes.ToLookup(n => n.ParentId ?? 0);

Func> buildTree = null;
buildTree = parentId => lookup[parentId]
    .Select(n => new NodeDto {
        Id = n.Id,
        Name = n.Name,
        Children = buildTree(n.Id)
    })
    .ToList();

var rootNodes = buildTree(0);

效能對比

方案適用場景記憶體首屏速度
懶惰載入大數據、深層級、生產環境低極快
一次性載入 + ToLookup<1000 節點、原型開發中快
遞迴 CTE + GroupBy報表匯出、離線分析高慢

總結

TreeView 載入策略選擇:生產環境必用懶惰載入。LINQ 在此場景下的角色是構建單層查詢,而非建構整棵樹。前端框架都支援按需載入,配合 HasChildren 欄位即可完美呈現展開圖示。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved