C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现

今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了:

首先创建节点类(我给它取名: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方面的问题,等我写好后再把代码分享出来,大家一起讨论!

时间: 2024-10-11 00:32:51

C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现的相关文章

C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制

在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Caching 我理解是在内容中实现,这种方法适用于单服务器的生产环境. 2.a Distributed Cache 分部式缓存实现. 3.Response Cache 这种方式我理解为客户端缓存. 今天我只用了第一种实现方法,内存中缓存,之所以用这种方法我是觉得我这里用缓存的初衷是为了减少访问数据库的次数,

创建无限极分类树型结构

先上效果图 顶级分类其实就是一级分类,二级分类也叫作一级分类的子分类,在这个基础上,子分类还可以拥有子分类,这样就构成了无限极分类. 接下来看具体实现的代码: 一.在控制器中按字段查询,查询出所有分类信息(id:该分类的ID值,cate_name:该分类的名称,pid:父ID,sorts:为显示标题顺序排序做准备,可不写.) 1 public function cate_display() 2 { 3 $cate = D('Cate'); 4 $field = array('id','cate_

js实现无限极分类

转载注明出处!!! 转载注明出处!!! 转载注明出处!!! 因为要实现部门通讯录,后台传来的数据是直接从数据库里拿的部门表,所以没有层级分类,只有parentId表示从属关系,所以分类的事情就交给我来做了. 不能说效率多高,只是说能实现了. 其实ACMer或者学过点算法和数据结构的应该知道这其实就是一个树,用数组存罢了,用数组存树的方法相信各位ACMer已经用的不要不要的了,所有并没有什么难度,知道思路就很好写了. 思路:获取到后台传来的数组dep,然后新建一个数组list,将dep遍历一遍,获

夺命雷公狗ThinkPHP项目之----企业网站8之栏目的添加完善(无限极分类的完成)

我们刚才只是完成了添加的一部分,但是我们的上级分类也不能永远都是只有一个死的嘛,所以我们需要对她进行修改: 我们先将add方法里面的数据查出来再说: 然后在模板页进行遍历: 展示效果如下所示: 虽然是出现了,但是没有向我们平常时候见到的无限极分类一样噢,一般比如分类 多多,分类下面的 好多美女啊 是多多的下级分类,那么好多美女啊他前面是有几个空格之类的隔开, 那么我们就需要在model层里面对她进行排序的设置了: <?php namespace Admin\Model; use Think\Mo

java简单的无限极分类

这是一个比较简单的无限极分类,适用于各种编程语言. 这个原理是 一次性把数据库所有分类读取出来之后再根据pid来排序. 比较简单,好理解. public static List<Category> cates; private static List<Category> tmpCates = new ArrayList<Category>(); public static void main(String[] args) {     init();     List&l

DotNet菜鸟入门之无限极分类(一)设计篇

写这个教程的原因,是因为,无限极分类,在许多项目中,都用得到.而对于新手来说,不是很好理解,同时,操作上也有一些误区或者不当之处.所以我就斗胆,抛砖引玉一下,已一个常见的后台左侧频道树为例子,讲解一下剖析一下无限极分类的实战操作. 既然是写给菜鸟的,那么我就不话结构图了,直接文字+代码来说明吧. 正文 无限极分类的关键就在于数据库设计时,进行了父类编号的记录,从而把所有的分类,链接了起来,成为一个链表样式的结构. 这次我要讲的无限极分类设计如下: (图1) 创建的表的sql语句如下,具体字段的说

thinkphp无限极分类

这里首先介绍一下,什么是无限极分类? 无限极分类简单点说就是将一个类分成多个子类,然后一个子类又可以分另外多个子类这样无限分下去,就好象windows可以新建一个文件夹,然后在这个文件夹里又可以建一些个文件夹,在文件夹底下还可以建一些文件夹一样 那用Thinkphp如何实现无限分类的呢? 下面看一下分类结果: 下面给出实例代码: 1.先创建Model文件并在里面定义两个方法,如下: <?php namespace app\admin\model; use think\Model; class C

PHP无限极分类

概述 ??在实际工作中,经常要用到无限极分类.如导航表等等.到网上一搜php无限极分类,很多,但好多都是一个,并且,写的很乱,代码很多,那些都不靠谱,还是自己捣鼓捣鼓无限极分类了.下面介绍两种无限极分类:递归,使用引用 数据准备 //初始化原始数据(id=>编号,name=>显示名称,pid=>父级目录id,sort=>排序顺序) $data[1] = array('id'=>'1','name'=>'一级目录A','pid'=>'0','sort'=>'1

php递归无限极分类

递归无限级分类有几种形式,我这里只举例比较常用的三种: 第一种:返回有排序的数组: <?php $data = array( 1 => array( 'id' => 1, 'pid' => 0, 'user_name' => 'one', ), 2 => array( 'id' => 2, 'pid' => 1, 'user_name' => 'two', ), 3 => array( 'id' => 3, 'pid' => 1, '