C#無限極分類樹-創建-排序-讀取 用Asp.Net Core+EF實現

来源:http://www.cnblogs.com/xwei/archive/2016/12/12/6166320.html
-Advertisement-
Play Games

今天做一個管理後臺菜單,想著要用無限極分類,記得園子里還是什麼地方見過這種寫法,可今天找了半天也沒找到,沒辦法靜下心來自己寫了: 首先創建節點類(我給它取名:AdminUserTree): 為無限極分類填充數據,由於考慮到示來管理後臺每個頁面都會調用到,這裡我為控制器創建了一個基類方法 控制器(Co ...


今天做一個管理後臺菜單,想著要用無限極分類,記得園子里還是什麼地方見過這種寫法,可今天找了半天也沒找到,沒辦法靜下心來自己寫了:

首先創建節點類(我給它取名:AdminUserTree):

 1 /// <summary>
 2     /// 無限極節點類
 3     /// </summary>
 4     public class AdminUserTree
 5     {
 6         /// <summary>
 7         /// 節點信息
 8         /// </summary>
 9         public int NodeID { get; set; }
10         /// <summary>
11         /// 節點名稱
12         /// </summary>
13         public string NodeName { get; set; }
14         /// <summary>
15         /// 父節點ID
16         /// </summary>
17         public int ParentID { get; set; }
18         /// <summary>
19         /// 對應的鏈接地址
20         /// </summary>
21         public string Url { get; set; }
22         public int? PermissionID { get; set; }
23         public int? OrderID { get; set; }
24         public string Location { get; set; }        
25         public string comment { get; set; }           
26         public string ImageUrl { get; set; }
27         /// <summary>
28         /// 層級
29         /// </summary>
30         public int level { get; set; }
31         /// <summary>
32         /// 子節點數目(很重要)
33         /// </summary>
34         public int childNumberl { get; set; }
35 
36         /// <summary>
37         ///  子節點 (子節點是一個List)這種用法叫什麼?
38         /// </summary>
39         public List<AdminUserTree> childNode { get; set; }
40     }

為無限極分類填充數據,由於考慮到示來管理後臺每個頁面都會調用到,這裡我為控制器創建了一個基類方法

 1 /// <summary>
 2     /// 管理頁面基類(MVC Controller)
 3     /// </summary>
 4     public class AdminBase: Controller
 5     {
 6         /// <summary>
 7         /// EF數據訪問配置
 8         /// </summary>
 9         private readonly ApplicationDbContext _basecontext;
10 
11         /// <summary>
12         /// 管理菜單 這裡是基數,聲明為屬性以便控制器裡面可以用到
13         /// </summary>
14         public AdminUserTree leftMenu { get; set; }
15 
16 
17         public AdminBase(ApplicationDbContext context)
18         {
19             _basecontext = context;
20             //初始化無限極分類管理菜單
21             buildtree();
22         }
23 
24         /// <summary>
25         /// 建立無限極節點樹-管理菜單
26         /// </summary>
27         public void buildtree()
28         {
29             AdminUserTree result = new AdminUserTree();
30             //初始化一個節點做為根節點
31             result.NodeID = 0;
32             result.NodeName= "管理員菜單";
33             result.Url = "";
34             result.ParentID = -1;
35             result.Location = "";
36             result.OrderID = 0;
37             result.comment = "";
38             result.ImageUrl = "";
39             result.PermissionID = 0;
40             result.level = 0;
41             result.childNumberl = 0;
42             //把根節點傳遞給遞歸方法去創建子節點
43             result.childNode=BuildMenuTree(result, -1);
44             leftMenu = result;
45         }
46 
47         /// <summary>
48         /// 遞歸創建子節點方法
49         /// </summary>
50         /// <param name="node">要為其分配子節點的父級節點</param>
51         /// <param name="levelID">層級關係</param>
52         /// <returns></returns>
53         protected  List<AdminUserTree> BuildMenuTree(AdminUserTree node, int levelID)
54         {
55             var listtree = _basecontext.Admintree;
56 
57             //從資料庫中取出node節點的全部子節點 條件:m.ParentID==node.NodeID
58             List<AdminUserTree> lt  =  listtree.Where(m => m.ParentID==node.NodeID )
59                                             .Select(m=>new AdminUserTree() {
60                                             NodeID =m.NodeID
61                                             ,NodeName=m.NodeName
62                                             ,Url=m.Url
63                                             ,ParentID=m.ParentID
64                                             ,Location=m.Location
65                                             ,OrderID=m.OrderID
66                                             ,comment=m.comment
67                                             ,ImageUrl=m.ImageUrl
68                                             ,PermissionID=m.PermissionID})
69                                             .ToList();
70 
71             if (lt != null)
72             {
73                 //節點深度
74                 node.level = levelID + 1;
75                 //子節點數量,便於前端遞歸輸出時調用
76                 node.childNumberl = lt.Count;
77                 for (int i = 0; i < lt.Count; i++)               
78                 {
79                     //遞歸調用創建子節點
80                     lt[i].childNode = BuildMenuTree(lt[i], node.level);
81                 }
82                 return lt;
83 
84             }
85             else {
86                 return null;
87             }            
88 
89          }
90         
91     }

控制器(Controller)繼承及調用代碼:

 1   public class AdminTreeController : AdminBase
 2     {
 3         private readonly ApplicationDbContext _context;
 4 
 5         
 6         public AdminTreeController(ApplicationDbContext context):base(context)
 7         {
 8             _context = context;    
 9         }
10 
11         // GET: AdminTree
12         public async Task<IActionResult> Index(int id=1)
13         {
14             var treelist = _context.Admintree;
15             var pageOption = new WeiPagerOption
16             {
17                 CurrentPage = id,
18                 PageSize = 15,
19                 Total = await treelist.CountAsync(),
20                 RouteUrl = "/Admintree/Index",
21                 pageNumStep = 5
22             };
23 
24             //分頁參數
25             ViewBag.PagerOption = pageOption;
26 
27             //無限極分類菜單綁定在這裡
28             ViewBag.mainMenu = leftMenu;
29 
30             //返回主要數據
31             return View(await treelist.OrderByDescending(b => b.OrderID).Skip((pageOption.CurrentPage - 1) * pageOption.PageSize).Take(pageOption.PageSize).ToListAsync());
32         }
33

View層代碼:

  1 @model IEnumerable<Hxwei.WebWQSF.Models.AdminTreeModel>
  2 @using Hxwei.WebWQSF;
  3 @using Hxwei.WebWQSF.Controllers;
  4 @using System.Text;
  5 @{
  6     ViewData["Title"] = "菜單管理";
  7 }
  8 @functions
  9 {
 10     public string getAdminMenu(AdminUserTree node)
 11     {
 12         StringBuilder sb = new StringBuilder();
 13 
 14         List<AdminUserTree> ls = node.childNode;
 15         if(ls.Count>0)
 16         {
 17             //遍歷每個子節點以輸出,這裡用到了排序ls.OrderBy(m => m.OrderID)
 18             foreach (var r in ls.OrderBy(m => m.OrderID))
 19             {
 20                 if (r.childNumberl > 0)
 21                 {
 22                     //當存在子菜單時的方法,這裡會有遞歸調用
 23                     sb.Append("<div class=\"btn-group\">");
 24                     sb.Append("<button type=\"button\" class=\"btn btn-default dropdown-toggle\" data-toggle=\"dropdown\">");
 25                     sb.Append(r.NodeName);
 26                     sb.Append("<span class=\"caret\"></span>");
 27                     sb.Append("</button>");
 28                     sb.Append("<ul class=\"dropdown-menu\" role=\"menu\">");
 29                     //遞歸調用
 30                     sb.Append(getAdminMenu(r));
 31                     sb.Append("</ul>");
 32                     sb.Append("</div>");
 33 
 34                 }
 35                 else
 36                 {
 37                     //當不存在子菜單時輸出
 38                     string ntext = string.Format("<li><a href=\"{0}\">{1}</a></li>",r.Url,r.NodeName);
 39                     sb.Append(ntext);
 40 
 41                 }
 42             }
 43 
 44         }
 45 
 46 
 47         return sb.ToString();
 48     }
 49 }
 50 <div class="row">
 51     <div class="col-md-3 navbar-inverse">
 52         <div class="btn-group-vertical col-md-10">
 53             
 54             <button type="button" class="btn btn-default">@ViewBag.mainMenu.NodeName</button>
 55             @Html.Raw(getAdminMenu(ViewBag.mainMenu));
 56           
 57         </div>
 58 
 59     </div>
 60     <div class="col-md-9">
 61         <h2>Index</h2>
 62 
 63         <p>
 64             <a asp-action="Create">Create New</a>
 65         </p>
 66         <table class="table">
 67             <thead>
 68                 <tr>
 69                     <th>
 70                         @Html.DisplayNameFor(model => model.NodeName)
 71                     </th>
 72                     <th>
 73                         @Html.DisplayNameFor(model => model.ParentPath)
 74                     </th>
 75                     <th>
 76                         @Html.DisplayNameFor(model => model.OrderID)
 77                     </th>
 78                     <th>
 79                         @Html.DisplayNameFor(model => model.Url)
 80                     </th>
 81                     <th></th>
 82                 </tr>
 83             </thead>
 84             <tbody>
 85                 @foreach (var item in Model)
 86                 {
 87                 <tr>
 88                     <td>
 89                         @Html.DisplayFor(modelItem => item.NodeName)
 90                     </td>
 91                     <td>
 92                         @Html.DisplayFor(modelItem => item.ParentPath)
 93                     </td>
 94                     <td>
 95                         @Html.DisplayFor(modelItem => item.OrderID)
 96                     </td>
 97                     <td>
 98                         @Html.DisplayFor(modelItem => item.Url)
 99                     </td>
100                     <td>
101                         <a asp-action="Edit" asp-route-id="@item.NodeID">Edit</a> |
102                         <a asp-action="Details" asp-route-id="@item.NodeID">Details</a> |
103                         <a asp-action="Delete" asp-route-id="@item.NodeID">Delete</a>
104                     </td>
105                 </tr>
106                 }
107             </tbody>
108             <tr><td colspan="5" align="center"><pager pager-option="ViewBag.PagerOption as WeiPagerOption"></pager></td></tr>
109         </table>
110     </div>
111 </div>

最後生成的菜單瀏覽器展示效果如下:

寫了很久簡單三層,最近決定用一下ASP.NET MVC,最近剛瞭解了一下ASP.NET MVC,目前最新的算是ASP.NET Core MVC,這個例子就是剛剛安裝了VS2017 RC後用ASP.NET Core MVC來實現的。學習階段希望與各位大神共勉,有不足的地方請多多指教!謝謝!

在做完這個類子後,我覺得後續還有可以優化的地方,我是從這幾個方面考慮的,希望高手給予指點:

1.這裡在構建無限極分類樹時我是多次調用資料庫查詢,如果數據量小的話想著是把數據一次取出然後傳遞後遞歸方法進行操作;由於用了EF,對於EF我也是個新手,只是剛剛會用,不知道EF本身會不會對這種類型的操作進行優化及數據緩存。

2.第二個方面是在無限極分類樹數據真充好後由於每個管理頁面都要調用這個樹的數據,考慮要對其進行緩存,如何緩存是我下一步要考慮的方法;

3.同時每個節點的許可權不同,由於每個用戶角色的不同許可權所能調用的菜單功能也不一致,這就存在了是為每一個用戶都緩存一棵樹還是全局共用一棵樹的問題,顯然前者是不科學的,應該是全員共用一棵樹的數據,只需要在View層顯示時加以許可權判斷就可以了。這也是我在下一步要考慮的。

後續會先解決以上提到第2和第3方面的問題,等我寫好後再把代碼分享出來,大家一起討論!

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 說到redis的Dict(字典),雖說演算法上跟市面上一般的Dict實現沒有什麼區別,但是redis的Dict有2個特殊的地方那就是它的rehash(重新散列)和它的字典節點單向鏈表。 以下是dict用到的結構: 由於樓主演算法能力有限:所以對哈希演算法沒有太深的瞭解,所以在這裡演算法就不詳寫了,大家有興趣 ...
  • redis里擁有一個靈活擴展且獲取表頭表尾複雜度為O(1)的雙端列表,分為list和listNode2部分組成。 list: listNode: 以下是雙向鏈表的實現原理: ...
  • yum(全稱為 Yellow dog Updater, Modified)是一個在Fedora和RedHat以及SUSE中的Shell前端軟體包管理器。基於RPM包管理,能夠從指定的伺服器自動下載RPM包並且安裝,可以自動處理依賴性關係,並且一次安裝所有依賴的軟體包,無須繁瑣地一次次下載、安裝。yu ...
  • Devicetree(設備樹)是用來描述系統硬體信息的樹模型,其旨在unify內核。通過bootloader將devicetree的信息傳給kernel,然後kernel根據這些設備描述初始化相應的板級驅動,達到一個內核多個平臺共用的目的。 ...
  • 新組裝了個 64 位電腦,i5 CPU,進入 ubuntu 後,又是一通搜索設置,整理如下,以備後用。 安裝 .dep 包 sudo dpkg -i [filename.dep] 在 ubuntu 中訪問 windows 分區 sudo ntfsfix [/dev/sda1] 安裝 flash 插件 ...
  • 根據Linux設備模型可知,一個現實的Linux設備和驅動通常都需要掛接在一種匯流排上,對於本身依附於PCI、USB等的設備而言,這自然不是問題,但是在嵌入式系統裡面,SoC系統中集成的獨立的外設控制器、掛接在 SoC 記憶體空間的外設等卻不依附於此類匯流排。基於這一背景,Linux設計了一種虛擬的匯流排,... ...
  • .NET 簡介 .NET是 Microsoft XML Web services 平臺。是微軟用來實現XML,Web Services,SOA(面向服務的體繫結構service-oriented architecture)和敏捷性的技術。 技術人員一般將微軟看成一個平臺廠商。微軟搭建技術平臺,而技術 ...
  • 本篇博文結合問題背景,介紹了筆者曾經嘗試過的阻止按鈕重覆提交的三種不可行方案,並詳細介紹了一種可行方案。有需要的可以參考下,希望對大家有所幫助。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...