C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现
今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了:
首先创建节点类(我给它取名:AdminUserTree):
/// <summary>
/// 无限极节点类
/// </summary>
public class AdminUserTree
{
/// <summary>
/// 节点信息
/// </summary>
public int NodeID { get; set; }
/// <summary>
/// 节点名称
/// </summary>
public string NodeName { get; set; }
/// <summary>
/// 父节点ID
/// </summary>
public int ParentID { get; set; }
/// <summary>
/// 对应的链接地址
/// </summary>
public string Url { get; set; }
public int? PermissionID { get; set; }
public int? OrderID { get; set; }
public string Location { get; set; }
public string comment { get; set; }
public string ImageUrl { get; set; }
/// <summary>
/// 层级
/// </summary>
public int level { get; set; }
/// <summary>
/// 子节点数目(很重要)
/// </summary>
public int childNumberl { get; set; } /// <summary>
/// 子节点 (子节点是一个List)这种用法叫什么?
/// </summary>
public List<AdminUserTree> childNode { get; set; }
}
为无限极分类填充数据,由于考虑到示来管理后台每个页面都会调用到,这里我为控制器创建了一个基类方法
/// <summary>
/// 管理页面基类(MVC Controller)
/// </summary>
public class AdminBase: Controller
{
/// <summary>
/// EF数据访问配置
/// </summary>
private readonly ApplicationDbContext _basecontext; /// <summary>
/// 管理菜单 这里是基数,声明为属性以便控制器里面可以用到
/// </summary>
public AdminUserTree leftMenu { get; set; } public AdminBase(ApplicationDbContext context)
{
_basecontext = context;
//初始化无限极分类管理菜单
buildtree();
} /// <summary>
/// 建立无限极节点树-管理菜单
/// </summary>
public void buildtree()
{
AdminUserTree result = new AdminUserTree();
//初始化一个节点做为根节点
result.NodeID = ;
result.NodeName= "管理员菜单";
result.Url = "";
result.ParentID = -;
result.Location = "";
result.OrderID = ;
result.comment = "";
result.ImageUrl = "";
result.PermissionID = ;
result.level = ;
result.childNumberl = ;
//把根节点传递给递归方法去创建子节点
result.childNode=BuildMenuTree(result, -);
leftMenu = result;
} /// <summary>
/// 递归创建子节点方法
/// </summary>
/// <param name="node">要为其分配子节点的父级节点</param>
/// <param name="levelID">层级关系</param>
/// <returns></returns>
protected List<AdminUserTree> BuildMenuTree(AdminUserTree node, int levelID)
{
var listtree = _basecontext.Admintree; //从数据库中取出node节点的全部子节点 条件:m.ParentID==node.NodeID
List<AdminUserTree> lt = listtree.Where(m => m.ParentID==node.NodeID )
.Select(m=>new AdminUserTree() {
NodeID =m.NodeID
,NodeName=m.NodeName
,Url=m.Url
,ParentID=m.ParentID
,Location=m.Location
,OrderID=m.OrderID
,comment=m.comment
,ImageUrl=m.ImageUrl
,PermissionID=m.PermissionID})
.ToList(); if (lt != null)
{
//节点深度
node.level = levelID + ;
//子节点数量,便于前端递归输出时调用
node.childNumberl = lt.Count;
for (int i = ; i < lt.Count; i++)
{
//递归调用创建子节点
lt[i].childNode = BuildMenuTree(lt[i], node.level);
}
return lt; }
else {
return null;
} } }
控制器(Controller)继承及调用代码:
public class AdminTreeController : AdminBase
{
private readonly ApplicationDbContext _context; public AdminTreeController(ApplicationDbContext context):base(context)
{
_context = context;
} // GET: AdminTree
public async Task<IActionResult> Index(int id=)
{
var treelist = _context.Admintree;
var pageOption = new WeiPagerOption
{
CurrentPage = id,
PageSize = ,
Total = await treelist.CountAsync(),
RouteUrl = "/Admintree/Index",
pageNumStep =
}; //分页参数
ViewBag.PagerOption = pageOption; //无限极分类菜单绑定在这里
ViewBag.mainMenu = leftMenu; //返回主要数据
return View(await treelist.OrderByDescending(b => b.OrderID).Skip((pageOption.CurrentPage - ) * pageOption.PageSize).Take(pageOption.PageSize).ToListAsync());
}
}
View层代码:
@model IEnumerable<Hxwei.WebWQSF.Models.AdminTreeModel>
@using Hxwei.WebWQSF;
@using Hxwei.WebWQSF.Controllers;
@using System.Text;
@{
ViewData["Title"] = "菜单管理";
}
@functions
{
public string getAdminMenu(AdminUserTree node)
{
StringBuilder sb = new StringBuilder(); List<AdminUserTree> ls = node.childNode;
if(ls.Count>)
{
//遍历每个子节点以输出,这里用到了排序ls.OrderBy(m => m.OrderID)
foreach (var r in ls.OrderBy(m => m.OrderID))
{
if (r.childNumberl > )
{
//当存在子菜单时的方法,这里会有递归调用
sb.Append("<div class=\"btn-group\">");
sb.Append("<button type=\"button\" class=\"btn btn-default dropdown-toggle\" data-toggle=\"dropdown\">");
sb.Append(r.NodeName);
sb.Append("<span class=\"caret\"></span>");
sb.Append("</button>");
sb.Append("<ul class=\"dropdown-menu\" role=\"menu\">");
//递归调用
sb.Append(getAdminMenu(r));
sb.Append("</ul>");
sb.Append("</div>"); }
else
{
//当不存在子菜单时输出
string ntext = string.Format("<li><a href=\"{0}\">{1}</a></li>",r.Url,r.NodeName);
sb.Append(ntext); }
} } return sb.ToString();
}
}
<div class="row">
<div class="col-md-3 navbar-inverse">
<div class="btn-group-vertical col-md-10"> <button type="button" class="btn btn-default">@ViewBag.mainMenu.NodeName</button>
@Html.Raw(getAdminMenu(ViewBag.mainMenu)); </div> </div>
<div class="col-md-9">
<h2>Index</h2> <p>
<a asp-action="Create">Create New</a>
</p>
<table class="table">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.NodeName)
</th>
<th>
@Html.DisplayNameFor(model => model.ParentPath)
</th>
<th>
@Html.DisplayNameFor(model => model.OrderID)
</th>
<th>
@Html.DisplayNameFor(model => model.Url)
</th>
<th></th>
</tr>
</thead>
<tbody>
@foreach (var item in Model)
{
<tr>
<td>
@Html.DisplayFor(modelItem => item.NodeName)
</td>
<td>
@Html.DisplayFor(modelItem => item.ParentPath)
</td>
<td>
@Html.DisplayFor(modelItem => item.OrderID)
</td>
<td>
@Html.DisplayFor(modelItem => item.Url)
</td>
<td>
<a asp-action="Edit" asp-route-id="@item.NodeID">Edit</a> |
<a asp-action="Details" asp-route-id="@item.NodeID">Details</a> |
<a asp-action="Delete" asp-route-id="@item.NodeID">Delete</a>
</td>
</tr>
}
</tbody>
<tr><td colspan="" align="center"><pager pager-option="ViewBag.PagerOption as WeiPagerOption"></pager></td></tr>
</table>
</div>
</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方面的问题,等我写好后再把代码分享出来,大家一起讨论!
C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现的更多相关文章
- C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制
在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制. 关于.Net Core的缓存,官方有三种实现: 1.In Memory Cachi ...
- sqlalchemy tree 树形分类 无限极分类的管理。预排序树,左右值树。sqlalchemy-mptt
简介: 无限极分类是一种比较常见的数据格式,生成组织结构,生成商品分类信息,权限管理当中的细节权限设置,都离不开无限极分类的管理. 常见的有链表式,即有一个Pid指向上级的ID,以此来设置结构.写的时 ...
- 无限极分类php实现—查子孙树、家谱树
1.本文更新日期:2018/05/20 , 亲测可用,在原有基础上进行增强和 详细化 . 2.面包屑导航 和 子孙树 效果图如下: 3.代码: <?php // 无限级分类中,查家谱树(面包屑导 ...
- js实现无限极分类
转载注明出处!!! 转载注明出处!!! 转载注明出处!!! 因为要实现部门通讯录,后台传来的数据是直接从数据库里拿的部门表,所以没有层级分类,只有parentId表示从属关系,所以分类的事情就交给我来 ...
- 夺命雷公狗ThinkPHP项目之----企业网站8之栏目的添加完善(无限极分类的完成)
我们刚才只是完成了添加的一部分,但是我们的上级分类也不能永远都是只有一个死的嘛,所以我们需要对她进行修改: 我们先将add方法里面的数据查出来再说: 然后在模板页进行遍历: 展示效果如下所示: 虽然是 ...
- DotNet菜鸟入门之无限极分类(一)设计篇
写这个教程的原因,是因为,无限极分类,在许多项目中,都用得到.而对于新手来说,不是很好理解,同时,操作上也有一些误区或者不当之处.所以我就斗胆,抛砖引玉一下,已一个常见的后台左侧频道树为例子,讲解一下 ...
- PHP实现菜单无限极分类
菜单数据 这里我们的菜单数据是临时数据, 没有从数据库中查询处理,数据基本和数据库中的的相似. 数据如下: $items = array( 1 => array('id' => 1, 'p ...
- php无限极分类以及递归(thinkphp)
php无限极分类: 无限极分类重点在于表的设计: 1在model中: class CatModel extends Model{ protected $cat = array(); public fu ...
- PHP无限极分类,多种方法|很简单,这里说的很详细,其它地方说的很不好懂
当你学习php无限极分类的时候,大家都觉得一个字"难"我也觉得很难,所以,现在都还在看,因为工作要用到,所以,就必须得研究研究. 到网上一搜php无限极分类,很多,但好多都是一 ...
随机推荐
- mssql 小技巧
代码1:查看sql的执行时间 SET STATISTICS PROFILE ON SET STATISTICS IO ON SET STATISTICS TIME ON select * from M ...
- 如何在 ASP.NET MVC 中集成 AngularJS(1)
介绍 当涉及到计算机软件的开发时,我想运用所有的最新技术.例如,前端使用最新的 JavaScript 技术,服务器端使用最新的基于 REST 的 Web API 服务.另外,还有最新的数据库技术.最新 ...
- Git学习笔记(9)——自定义配置
本文主要记录了Git的一些易用化的配置和别名的使用 配置Git的命令输出带有颜色,更加醒目 //配置输出颜色 $ git config --global color.ui true //取消输出颜色 ...
- javascript之-深入事件机制
作者:yuyuyu链接:https://zhuanlan.zhihu.com/p/24620643来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1.1 事件绑定的方式 ...
- 说说设计模式~门面模式(Facade)
返回目录 门面模式(Facade)属于结构型模式的一种,它符合面向对象的封装原则,但又不符合开闭原则,呵呵,今天我们主要说它的优点,不谈缺点. 定义 门面模式,是指提供一个统一的接口去访问多个子系统的 ...
- EF架构~linq to entity的随机排序问题
回到目录 对于从linq to sql迁移过来的开发者,对随机排序不会感到陌生,直接为datacontext添加一个方法再配合反射就可以实现随机排序了,代码如下: /// <summary> ...
- Atitit 记录方法调用参数上下文arguments
Atitit 记录方法调用参数上下文arguments 1.1. java java8 新的对象Parameter LocalVariableTable 本地变量表 MethodParamete ...
- iOS-数据持久化-偏好设置
一.简单介绍 很多iOS应用都支持偏好设置,比如保存用户名.密码.字体大小等设置,iOS提供了一套标准的解决方案来为应用加入偏好设置功能 每个应用都有个NSUserDefaults实例,通过它来存取偏 ...
- 手机页面的 HTML<meta> 标签使用与说明
name="viewport" 设置窗口(网页可绘制的区域) width="device-width" 应用宽与屏幕的宽一样的 (height同width) i ...
- RESTORE DATABASE的standby选项
RESTORE DATABASE [db1] FROM DISK = N'E:\Backup\db2.bak' , MOVE N'db1_Data' TO N'D:\Data\db2.MDF', MO ...