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
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...