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

在上一篇文章中我用递归方法实现了管理菜单,在上一节我也提到要考虑用缓存,也算是学习一下.Net Core的缓存机制。

关于.Net Core的缓存,官方有三种实现:

1.In Memory Caching 我理解是在内容中实现,这种方法适用于单服务器的生产环境。

2.a Distributed Cache 分部式缓存实现。

3.Response Cache 这种方式我理解为客户端缓存。

今天我只用了第一种实现方法,内存中缓存,之所以用这种方法我是觉得我这里用缓存的初衷是为了减少访问数据库的次数,而把访问数据库频率最高的数据转变为对象而放在缓存里。对于分部式说实话目前我也只是听说和了解原理,而没有做过实现,这里先不谈它。

微软官方提供的实现In Memory Caching 方法时有一个微软标准的示例,GitHub地址是  在这里

示例是用中间件实现的,经过一番学习,用示例里面提到的方法通过中间件实现了缓存,但怎么用到Controller里成了一个难题,也可能是我对中间件的了解不够深入吧!反正我是不知道该怎么办了!无耐之下,还是仔细研究了一下代码发现在中间件里面对缓存的调用(包括设置和取出)其实只在下面这段代码里实现:

 1 if(!_memoryCache.TryGetValue(cacheKey, out greeting))
 2             {
 3                 // fetch the value from the source
 4                 greeting = _greetingService.Greet("world");
 5
 6                 // store in the cache
 7                 _memoryCache.Set(cacheKey, greeting,
 8                     new MemoryCacheEntryOptions()
 9                     .SetAbsoluteExpiration(TimeSpan.FromMinutes(1)));
10                 _logger.LogInformation($"{cacheKey} updated from source.");
11             }
12             else
13             {
14                 _logger.LogInformation($"{cacheKey} retrieved from cache.");
15 }

也就是 _memoryCache.TryGetValue(cacheKey, out greeting)这一段负责从缓存中取出缓存内容;而_memoryCache.Set(cacheKey, greeting, new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes(1)));这个方法调用是把数据放到缓存里面的!

知道了这些以后就着手改造我的程序了:

1.创建IAdminTreeService.cs接口类:

public interface IAdminTreeService
    {
        /// <summary>
        /// 全部节点数据树
        /// </summary>
        AdminUserTree GetAllTreeData { get; }
    }

2.创建服务AdminTreeServices.cs,用于实现从数据库中取出管理菜单数据,用服务方式实现这种方式还是借鉴了官方示例的实现方式,这种实现是有其道理的。道理自己琢磨吧,最起码有得用接口统一。不再啰嗦直接代码:

  1  public class AdminTreeServices:IAdminTreeService
  2     {
  3         /// <summary>
  4         /// EF数据访问配置
  5         /// </summary>
  6         private readonly ApplicationDbContext _basecontext;
  7
  8         public AdminTreeServices(ApplicationDbContext context)
  9         {
 10             _basecontext = context;
 11         }
 12
 13         /// <summary>
 14         /// 建立无限极节点树-管理菜单
 15         /// </summary>
 16         /// <returns></returns>
 17         public AdminUserTree GetAllTreeData
 18         {
 19             get
 20             {
 21                 AdminUserTree result = new AdminUserTree();
 22                 //初始化一个节点做为根节点
 23                 result.NodeID = 0;
 24                 result.Text = "管理员菜单";
 25                 result.Url = "";
 26                 result.ParentID = -1;
 27                 result.Location = "";
 28                 result.OrderID = 0;
 29                 result.Comment = "来源为数据库";
 30                 result.ImageUrl = "";
 31                 result.PermissionID = 0;
 32                 result.Level = 0;
 33                 result.ChildNumberl = 0;
 34                 //把根节点传递给递归方法去创建子节点
 35                 result.ChildNode = BuildMenuTree(result, -1);
 36                 return result;
 37
 38             }
 39
 40         }
 41
 42
 43         /// <summary>
 44         /// 递归创建子节点方法
 45         /// </summary>
 46         /// <param name="node">要为其分配子节点的父级节点</param>
 47         /// <param name="levelID">层级关系</param>
 48         /// <returns></returns>
 49         protected List<AdminUserTree> BuildMenuTree(AdminUserTree node, int levelID)
 50         {
 51             var listtree = _basecontext.Admintree;
 52
 53             //从数据库中取出node节点的全部子节点 条件:m.ParentID==node.NodeID
 54             List<AdminUserTree> lt = listtree.Where(m => m.ParentID == node.NodeID)
 55                                             .Select(m => new AdminUserTree()
 56                                             {
 57                                                 NodeID = m.NodeID
 58                                             ,
 59                                                 Text = m.Text
 60                                             ,
 61                                                 Url = m.Url
 62                                             ,
 63                                                 ParentID = m.ParentID
 64                                             ,
 65                                                 Location = m.Location
 66                                             ,
 67                                                 OrderID = m.OrderID
 68                                             ,
 69                                                 Comment = m.Comment
 70                                             ,
 71                                                 ImageUrl = m.ImageUrl
 72                                             ,
 73                                                 PermissionID = m.PermissionID
 74                                             })
 75                                             .ToList();
 76
 77             if (lt != null)
 78             {
 79                 //节点深度
 80                 node.Level = levelID + 1;
 81                 //子节点数量,便于前端递归输出时调用
 82                 node.ChildNumberl = lt.Count;
 83                 for (int i = 0; i < lt.Count; i++)
 84                 {
 85                     //递归调用创建子节点
 86                     lt[i].ChildNode = BuildMenuTree(lt[i], node.Level);
 87                 }
 88                 return lt;
 89
 90             }
 91             else
 92             {
 93                 return null;
 94             }
 95
 96
 97
 98
 99         }
100
101     }

AdminTreeServices

3.管理页面基类 AdminBase.cs:

 1 public class AdminBase: Controller
 2     {
 3         /// <summary>
 4         /// EF数据访问配置
 5         /// </summary>
 6         private readonly ApplicationDbContext _basecontext;
 7         private readonly IAdminTreeService _adminTreeService;
 8         private readonly ILogger<AdminUserTree> _logger;
 9         private readonly IMemoryCache _memoryCache;
10
11
12         /// <summary>
13         /// 管理菜单 这里是基数,声明为属性以便控制器里面可以用到
14         /// </summary>
15         public AdminUserTree leftMenu { get; set; }
16
17
18         public AdminBase(ApplicationDbContext context,
19                             IMemoryCache memoryCache,
20                             ILogger<AdminUserTree> logger,
21                             IAdminTreeService adminTreeService)
22         {
23             _basecontext = context;
24             //初始化无限极分类管理菜单
25             _logger = logger;
26             _adminTreeService = adminTreeService;
27             _memoryCache = memoryCache;
28             leftMenu = GetAdminTreeByCache();
29         }
30
31         /// <summary>
32         /// 从缓存中读取节点树
33         /// </summary>
34         /// <param name="httpContext"></param>
35         /// <returns></returns>
36         public AdminUserTree GetAdminTreeByCache()
37         {
38             string cacheKey = "AdminTree-Base";
39             AdminUserTree adminTree;
40
41             //获取缓存内容的一种方式
42             // greeting = _memoryCache.Get(cacheKey) as string;
43
44             //另一种获取缓存内容的方式,
45            // alternately, TryGet returns true if the cache entry was found
46             if (!_memoryCache.TryGetValue(cacheKey, out adminTree))
47             {
48                 //缓存中不存在该内容,从数据接口中通过访问数据库获取。
49                 adminTree = _adminTreeService.GetAllTreeData;
50
51                 // 绝对过期时间方法,在设置缓存时3分钟后过期
52                 //_memoryCache.Set(cacheKey, adminTree,
53                 //    new MemoryCacheEntryOptions()
54                 //    .SetAbsoluteExpiration(TimeSpan.FromMinutes(3)));
55                 //相对过期时间方法,相对于最后一次调用后3分钟过期
56                 _memoryCache.Set(cacheKey, adminTree,
57                     new MemoryCacheEntryOptions()
58                     .SetSlidingExpiration(TimeSpan.FromMinutes(3)));
59                 //记录日志
60                 _logger.LogInformation($"{cacheKey} From Data."+DateTime.Now.AddMinutes(3).ToString());
61             }
62             else
63             {
64                 //记录日志,这里表示当前数据是从缓存中读取的。
65                 _logger.LogInformation($"{cacheKey} From Cacha."+DateTime.Now.ToString());
66             }
67
68             return adminTree;
69
70         }
71 }

AdminBase

4.最后不要忘记了在Startup.cs中加入以下代码 :

1 public void ConfigureServices(IServiceCollection services)
2         {
3             …………
4              services.AddMemoryCache();
5
6              services.AddTransient<IAdminTreeService, AdminTreeServices>();
7 }

在这里基本就实现了通过缓存读取数据了!至于Controller中的实现没有变化请参考我的上篇随笔:

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

为了方便阅读这里再放一遍菜单节点类代码:

 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 Text { 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     }

最后把运行时日志截图放出来:

首次访问:

上面有很多的数据库访问语句,日志提示数据来源与数据库

再次访问:

这里就是直接从缓存中读取出来的内容了!

好了今天的内容就写到这里。

按照先前的计划,下一步该研究一下用户及权限的内容了,这次我打算研究一下 ASP.NET Identity 身份验证和基于角色的授权,网上有很多相关的资料了,可我还是没有看明白怎么和我实际的项目相结合。估计要花几天时间了!

时间: 2024-10-22 08:48:02

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

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

今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了: 首先创建节点类(我给它取名:AdminUserTree): 1 /// <summary> 2 /// 无限极节点类 3 /// </summary> 4 public class AdminUserTree 5 { 6 /// <summary> 7 /// 节点信息 8 /// </summary> 9 public int

创建无限极分类树型结构

先上效果图 顶级分类其实就是一级分类,二级分类也叫作一级分类的子分类,在这个基础上,子分类还可以拥有子分类,这样就构成了无限极分类. 接下来看具体实现的代码: 一.在控制器中按字段查询,查询出所有分类信息(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, '