首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> .NET 網頁程式設計 >> 關於.NET

LINQ to SQL 遞歸構建 TreeView 導航選單:從資料庫設計到程式碼實作

     編輯:關於.NET

資料庫設計:自關聯階層結構

PDM 模型

  • MODULE_TYPE (模組分類):ID、PARENT_ID (自關聯 FK)、NAME、ORDER_ID
  • MODULE (模組/葉子節點):MODULE_TYPE_ID (FK 至分類)、TAG、NAME、MODULE_URL

SQL 建表腳本 (SQL Server 2005)

CREATE TABLE [dbo].[MODULE_TYPE](
    [ID] [varchar](15) NOT NULL PRIMARY KEY,
    [PARENT_ID] [varchar](15) NULL REFERENCES MODULE_TYPE(ID),
    [NAME] [varchar](40) NOT NULL,
    [ORDER_ID] [int] NOT NULL
);

CREATE TABLE [dbo].[MODULE](
    [ID] [varchar](15) NOT NULL PRIMARY KEY,
    [MODULE_TYPE_ID] [varchar](15) NOT NULL REFERENCES MODULE_TYPE(ID),
    [TAG] [varchar](40) NOT NULL,
    [NAME] [varchar](40) NOT NULL,
    [MODULE_URL] [varchar](200) NULL,
    [ORDER_ID] [int] NOT NULL
);

-- 範例資料
INSERT INTO MODULE_TYPE VALUES ('0000000001', NULL, '分類 1', 10);
INSERT INTO MODULE_TYPE VALUES ('0000000011', '0000000001', '分類11', 11);
INSERT INTO MODULE_TYPE VALUES ('0000000012', '0000000001', '分類12', 12);
INSERT INTO MODULE_TYPE VALUES ('0000000002', NULL, '分類 2', 20);
-- ... 略

LINQ to SQL 實體類別 (sqlmetal 產生)

實體類別圖

  • MODULE_TYPE 擁有 MODULE_TYPE_MODULE_TYPE (子分類集合) 與 MODULE (模組集合) 導航屬性
  • MODULE 擁有 MODULE_TYPE 父分類導航屬性

遞歸載入 TreeView 完整程式碼

private void LoadModuleTree()
{
    using (var ctx = new DMN.ZXKP())
    {
        // 1. 取得根分類 (PARENT_ID IS NULL)
        var rootTypes = from m in ctx.MODULE_TYPE
                        where m.PARENT_ID == null
                        orderby m.ORDER_ID
                        select m;

        TreeNode rootNode = new TreeNode("功能模組");
        tvMenu.Nodes.Add(rootNode);

        foreach (var type in rootTypes)
        {
            TreeNode node = new TreeNode
            {
                Text = type.NAME,
                ToolTip = type.NAME
            };
            rootNode.ChildNodes.Add(node);
            AddSubNodes(node, type); // 遞歸
            node.Expanded = false;
        }
    }
}

private void AddSubNodes(TreeNode parentNode, MODULE_TYPE currentType)
{
    using (var ctx = new DMN.ZXKP()) // 或傳入共用 DataContext
    {
        // 2. 遞歸載入子分類
        foreach (var subType in currentType.MODULE_TYPE_MODULE_TYPE.OrderBy(t => t.ORDER_ID))
        {
            TreeNode subNode = new TreeNode
            {
                Text = subType.NAME,
                ToolTip = subType.NAME
            };
            parentNode.ChildNodes.Add(subNode);
            AddSubNodes(subNode, subType); // 繼續遞歸
        }

        // 3. 載入該分類下的模組 (葉子節點)
        foreach (var module in currentType.MODULE.OrderBy(m => m.ORDER_ID))
        {
            TreeNode leafNode = new TreeNode
            {
                Text = module.NAME,
                ToolTip = module.NAME,
                NavigateUrl = module.MODULE_URL // 超連結導航
            };
            parentNode.ChildNodes.Add(leafNode);
        }
    }
}

執行效果

TreeView 效果

效能優化建議

  1. 單一 DataContext:遞歸過程共用一個 DataContext,避免重複查詢
  2. 預先載入扁平化:一次性 LoadWith 所有分類與模組,記憶體中遞歸組裝 TreeNode
  3. 分頁/虛擬化:節點過萬時啟用 TreeView 虛擬模式
  4. 快取策略:選單結構變動低,適合 HttpRuntime.Cache 或記憶體快取

擴展:支援多語系、權限控管

// 權限過濾範例
var allowedModules = from m in currentType.MODULE
                     where UserHasPermission(m.TAG)
                     select m;
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved