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里成了一个难题,也可能是我对中间件的了解不够深入吧!反正我是不知道该怎么办了!无耐之下,还是仔细研究了一下代码发现在中间件里面对缓存的调用(包括设置和取出)其实只在下面这段代码里实现:
if(!_memoryCache.TryGetValue(cacheKey, out greeting))
{
// fetch the value from the source
greeting = _greetingService.Greet("world"); // store in the cache
_memoryCache.Set(cacheKey, greeting,
new MemoryCacheEntryOptions()
.SetAbsoluteExpiration(TimeSpan.FromMinutes()));
_logger.LogInformation($"{cacheKey} updated from source.");
}
else
{
_logger.LogInformation($"{cacheKey} retrieved from cache.");
}
也就是 _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,用于实现从数据库中取出管理菜单数据,用服务方式实现这种方式还是借鉴了官方示例的实现方式,这种实现是有其道理的。道理自己琢磨吧,最起码有得用接口统一。不再啰嗦直接代码:
public class AdminTreeServices:IAdminTreeService
{
/// <summary>
/// EF数据访问配置
/// </summary>
private readonly ApplicationDbContext _basecontext; public AdminTreeServices(ApplicationDbContext context)
{
_basecontext = context;
} /// <summary>
/// 建立无限极节点树-管理菜单
/// </summary>
/// <returns></returns>
public AdminUserTree GetAllTreeData
{
get
{
AdminUserTree result = new AdminUserTree();
//初始化一个节点做为根节点
result.NodeID = ;
result.Text = "管理员菜单";
result.Url = "";
result.ParentID = -;
result.Location = "";
result.OrderID = ;
result.Comment = "来源为数据库";
result.ImageUrl = "";
result.PermissionID = ;
result.Level = ;
result.ChildNumberl = ;
//把根节点传递给递归方法去创建子节点
result.ChildNode = BuildMenuTree(result, -);
return 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
,
Text = m.Text
,
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;
} } }
AdminTreeServices
3.管理页面基类 AdminBase.cs:
public class AdminBase: Controller
{
/// <summary>
/// EF数据访问配置
/// </summary>
private readonly ApplicationDbContext _basecontext;
private readonly IAdminTreeService _adminTreeService;
private readonly ILogger<AdminUserTree> _logger;
private readonly IMemoryCache _memoryCache; /// <summary>
/// 管理菜单 这里是基数,声明为属性以便控制器里面可以用到
/// </summary>
public AdminUserTree leftMenu { get; set; } public AdminBase(ApplicationDbContext context,
IMemoryCache memoryCache,
ILogger<AdminUserTree> logger,
IAdminTreeService adminTreeService)
{
_basecontext = context;
//初始化无限极分类管理菜单
_logger = logger;
_adminTreeService = adminTreeService;
_memoryCache = memoryCache;
leftMenu = GetAdminTreeByCache();
} /// <summary>
/// 从缓存中读取节点树
/// </summary>
/// <param name="httpContext"></param>
/// <returns></returns>
public AdminUserTree GetAdminTreeByCache()
{
string cacheKey = "AdminTree-Base";
AdminUserTree adminTree; //获取缓存内容的一种方式
// greeting = _memoryCache.Get(cacheKey) as string; //另一种获取缓存内容的方式,
// alternately, TryGet returns true if the cache entry was found
if (!_memoryCache.TryGetValue(cacheKey, out adminTree))
{
//缓存中不存在该内容,从数据接口中通过访问数据库获取。
adminTree = _adminTreeService.GetAllTreeData; // 绝对过期时间方法,在设置缓存时3分钟后过期
//_memoryCache.Set(cacheKey, adminTree,
// new MemoryCacheEntryOptions()
// .SetAbsoluteExpiration(TimeSpan.FromMinutes(3)));
//相对过期时间方法,相对于最后一次调用后3分钟过期
_memoryCache.Set(cacheKey, adminTree,
new MemoryCacheEntryOptions()
.SetSlidingExpiration(TimeSpan.FromMinutes()));
//记录日志
_logger.LogInformation($"{cacheKey} From Data."+DateTime.Now.AddMinutes().ToString());
}
else
{
//记录日志,这里表示当前数据是从缓存中读取的。
_logger.LogInformation($"{cacheKey} From Cacha."+DateTime.Now.ToString());
} return adminTree; }
}
AdminBase
4.最后不要忘记了在Startup.cs中加入以下代码 :
public void ConfigureServices(IServiceCollection services)
{
…………
services.AddMemoryCache(); services.AddTransient<IAdminTreeService, AdminTreeServices>();
}
在这里基本就实现了通过缓存读取数据了!至于Controller中的实现没有变化请参考我的上篇随笔:
C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现
为了方便阅读这里再放一遍菜单节点类代码:
/// <summary>
/// 无限极节点类
/// </summary>
public class AdminUserTree
{
/// <summary>
/// 节点信息
/// </summary>
public int NodeID { get; set; }
/// <summary>
/// 节点名称
/// </summary>
public string Text { 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; }
}
最后把运行时日志截图放出来:
首次访问:

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

这里就是直接从缓存中读取出来的内容了!
好了今天的内容就写到这里。
按照先前的计划,下一步该研究一下用户及权限的内容了,这次我打算研究一下 ASP.NET Identity 身份验证和基于角色的授权,网上有很多相关的资料了,可我还是没有看明白怎么和我实际的项目相结合。估计要花几天时间了!
C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现之方法二:加入缓存机制的更多相关文章
- C#无限极分类树-创建-排序-读取 用Asp.Net Core+EF实现
今天做一个管理后台菜单,想着要用无限极分类,记得园子里还是什么地方见过这种写法,可今天找了半天也没找到,没办法静下心来自己写了: 首先创建节点类(我给它取名:AdminUserTree): /// & ...
- 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无限极分类,很多,但好多都是一 ...
随机推荐
- OOAD利器之UML基础
UML:Unified Modeling Language,即统一建模语言,简单地说就是一种有特殊用处的语言.本文是我初步学习UML的学习笔记,对于我们菜鸟码农来说,让我们做设计的可能性不大,但至少能 ...
- The Similarities and Differences Between C# and Java -- Part 1(译)
原文地址 目录 介绍(Introduction) 相似点(Similarities) 编译单位(Compiled Units) 命名空间(Namespaces) 顶层成员(类型)(Top Level ...
- [.net 面向对象程序设计深入](2)UML——在Visual Studio 2013/2015中设计UML用例图
[.net 面向对象程序设计深入](2)UML——在Visual Studio 2013/2015中设计UML用例图 1.用例图简介 定义:用例图主要用来描述“用户.需求.系统功能单元”之间的关系. ...
- JS获取剪贴板图片之后的格式选择与压缩问题
前言 某年某月的某一天,突然发现博客服务器上上传的图片都比较大,一些很小的截图都有几百kb,本来服务器带宽就慢,不优化一下说不过去. 问题细述 特别说明:本文代码因为只是用于我自己后台写markdow ...
- Hadoop 裡的 fsck 指令
Hadoop 裡的 fsck 指令,可檢查 HDFS 裡的檔案 (file),是否有 corrupt (毀損) 或資料遺失,並產生 HDFS 檔案系統的整體健康報告.報告內容,包括:Total blo ...
- ionic中关于ionicView 的生命周期
当我们来回切换页面时候,视图被缓存下来,不用每次再去new一个新的视图,可以大大地提高性能.当跳出一个视图后,视图的元素被保存在DOM中,它的作用域也就不在$watch的作用域内,当我们访问一个已经被 ...
- java compiler level does not match the version of the installed java project facet 解决方案
项目出现 java compiler level does not match the version of the installed java project facet 错误,一般是项目移植出现 ...
- springboot学习笔记(一)
一.什么是SpringBoot 描述:Spring Boot是Spring社区发布的一个开源项目,旨在帮助开发者快速并且更简单的构建项目.大多数SpringBoot项目只需要很少的配置文件.二.Spr ...
- Yii2-多表关联的用法示例
本篇博客是基于<活动记录(Active Record)>中对于AR表关联用法的介绍. 我会构造一个业务场景,主要是测试我比较存疑的各种表关联写法,而非再次介绍基础用法. 构造场景 订单ar ...
- java自定义类加载器
前言 java反射,最常用的Class.forName()方法.做毕设的时候,接收到代码字符串,通过 JavaCompiler将代码字符串生成A.class文件(存放在classpath下,也就是ec ...