让EFCore更疯狂些的扩展类库(二):查询缓存、分部sql、表名替换的策略配置
前言
上一篇介绍了扩展类库的功能简介,通过json文件配置sql语句 和 sql语句的直接执行,这篇开始说明sql配置的策略模块:策略管理器与各种策略的配置。
类库源码:github:https://github.com/skigs/EFCoreExtend
引用类库:nuget:https://www.nuget.org/packages/EFCoreExtend/
PM> Install-Package EFCoreExtend
策略管理器功能简介
用于管理策略 与 策略执行器和调用(目前分为三种策略执行器),目的为了让配置的sql语句更加简单、自动化等等。
1) 策略类型管理
a) 管理各种策略类型,用于初始化配置文件中的策略配置转换成对象
2) 策略对象配置
a) 通过 sql配置的执行器 的形参传递策略对象
b) 通过 配置文件(分为表和sql) 配置策略对象
c) 配置到 全局策略 中(策略管理器中)
d) 策略对象获取的优先级:通过执行器的形参传递的策略对象 > sql配置的策略对象 > 表配置的策略对象 > 全局策略中配置
3) 策略执行器(一般通过策略对象进行相应的处理)
a) 初始化型的策略执行器:这种类型的会在第一次调用GetExecutor的时候执行,只会执行一次,除非sql配置有改动
- 配置策略对象的初始化、替换表名、合并分部sql等的策略执行器
b) sql执行前的策略执行器:一般用于对SqlParameter进行解析到sql中
- foreach策略执行器:对SqlParameter或者某些数据类型(list/dictionary/model)进行遍历生成字串替换到sql中
c) sql执行时的策略执行器:一般用于缓存和日志记录
- sql与参数的日志记录策略执行器
- 查询缓存与清理策略执行器
表名替换策略
通过特定的标签代替表名在sql配置中呈现(该策略对象默认已经添加到全局策略中,因此并不一定要在配置文件中配置):
{
"policies": { //表配置的策略对象(会包含到表下的所有sql配置中)
//表名策略
"tname": {
//"tag": "##tname" //默认值为 ##tname
}
},
"sqls": {
"GetList": {
"sql": "select * from ##tableName where name=@name", // => select * from [Person] where name=@name
"type": "query",
"policies": { //sql配置的策略对象
//表名策略
"tname": {
"tag": "##tableName", //默认值为 ##tname
"prefix": "[", //前缀
"suffix": "]" //后缀
}
}
}
}
}
配置初始化:
public static void Init()
{
//加载配置
EFHelper.Services.SqlConfigMgr.Config.LoadDirectory(Directory.GetCurrentDirectory() + "/Datas");
//设置到全局策略中(一般用于设置 初始化型的策略对象),将策略对象设置到全局之后,会包含到所有配置中的
EFHelper.Services.SqlConfigMgr.PolicyMgr.SetGlobalPolicy(
//TableNamePolicy对象默认已经添加到全局策略中
new TableNamePolicy //表名策略在配置文件中呈现的key:tname(可以通过SqlConfigConst.TableNamePolicyName获取)
{
Tag = "##tname",
});
}
配置执行器调用:
public IReadOnlyList<Person> GetList()
{
tinfo = db.GetConfigTable<Person>();
return tinfo.GetExecutor().QueryUseModel<Person>(new
{
name = "tom"
}, null, null,
//通过参数传递策略对象(一般用于设置 sql执行前 或 执行时的策略对象,
// 而初始化型的一般在配置文件或全局策略中设置)
new[] { new SqlL2QueryCachePolicy() });
}
说明:
策略对象获取的优先级(如果策略对象设置到多个地方了): 执行器形参传递的策略对象 > sql配置的策略对象 > 表配置的策略对象 > 全局策略中配置
分部sql策略
分部sql目的为了将sql分部在不同的配置中,以便sql的可重用:
Person.json配置:
{
"sqls": {
"GetListSection": {
"sql": "select * from ##tname where #{WhereSec}",
//最终生成的sql:select * from Person where name=@name or addrid in (select id from Address where id=@addrid)
"type": "query",
"policies": {
//分部sql策略,以便将sql分部在不同的配置中(注意:分部策略是对sql的分部,可以在分部sql下再进行分部sql(子分部),但是不会继承分部sql中的policies(策略对象)等的配置)
"section": {
//"tagPrefix": "#{", //策略前缀标记符,默认为 #{
//"tagSuffix": "}", //策略后缀标记符,默认为 }
"sqlNames": [ "WhereSec" ] //指定sql的名称(同表下的SqlName)
//"tableSqlNames": { //指定其他表的sql名称(key为TableName,value为SqlName)
//}
}
}
},
"WhereSec": {
"sql": " #{WhereSec1} or addrid in (#{Address.ListSec}) ",
"type": "nonexecute", //不用于执行的sql类型
"policies": {
"section": {
"sqlNames": [ "WhereSec1" ],
"tableSqlNames": { //指定其他表的sql名称(key为TableName,value为SqlName)
"Address": "ListSec"
}
}
}
},
"WhereSec1": {
"sql": "name=@name",
"type": "nonexecute"
}
}
}
Address.json:
{
"sqls": {
"ListSec": {
"sql": "select id from ##tname where #{WhereSec}",
"type": "nonexecute",
"policies": {
"section": {
"sqlNames": [ "WhereSec" ] //指定sql的名称(同表下的SqlName)
}
}
},
"WhereSec": {
"sql": "id=@addrid",
"type": "nonexecute"
}
}
}
配置执行器调用:
public IReadOnlyList<Person> GetListSection()
{
tinfo = db.GetConfigTable<Person>();
return tinfo.GetExecutor().QueryUseModel<Person>(new
{
name = name,
addrid = ,
});
}
查询缓存与缓存清理策略
查询缓存分为 一级缓存 和 二级缓存。
一级查询缓存策略
一级缓存仅作用于SqlConfigExecutor对象中,而且不能设置缓存过期时间。
配置:
{
"sqls": {
"GetListL1Cache": {
"sql": "select * from ##tname where name=@name",
"type": "query",
"policies": {
"l1cache": {} //一级查询缓存,仅作用于SqlConfigExecutor对象
}
}
}
}
配置执行器调用:
public void GetListL1Cache()
{
var tinfo = db.GetConfigTable<Person>();
var exc = tinfo.GetExecutor();
var q1 = exc.QueryUseModel<Person>(new { name = _name });
var q2 = exc.QueryUseModel<Person>(new { name = _name });
//一级缓存作用于SqlConfigExecutor,那么同一个SqlConfigExecutor对象下,
// 相同的sql和SqlParameter获取的数据是一样的
Assert.True(q1 == q2);
" });
//参数变了
Assert.True(q1 != q3);
}
二级查询缓存策略
二级查询缓存,作用于整个程序运行期间,也可配置到Redis中,如果同时配置了二级缓存和一级缓存默认是使用二级缓存(策略执行器的优先级有关)。
配置:
{
"name": "Person",
"policies": {
//二级查询缓存,作用于整个程序运行期间 / 或者跨进程分布式(Redis),如果同时配置了二级缓存和一级缓存默认时使用二级缓存(策略执行器的优先级有关)
"l2cache": {
//"type":"", //缓存的类型(Query默认为:query, Scalar默认为:scalar)
"expiry": { //注意如果没有设置expiry的date/span,那么缓存不会过期的
//"date": "2018-01-01", //指定缓存的过期日期
//"span": "00:00:03" //指定缓存的过期间隔(换算日期为:当前时间 + 时间间隔)
//"isUpdateEach": true //是否每次获取缓存之后更新过期时间(这个属性 + span属性来进行模拟session访问更新过期时间)
}
}
},
"sqls": {
"CountL2Cache": {
"sql": "select count(*) from ##tname",
"type": "scalar",
"policies": {
"l2cache": {
"expiry": {
"span": "00:00:03", //指定缓存的过期间隔,这里设置为3秒
"isUpdateEach": true //每次获取缓存之后更新过期时间
}
}
}
}
}
}
配置执行器调用:
public int CountL2Cache(TimeSpan? span = null)
{
var tinfo = db.GetConfigTable<Person>();
if (span.HasValue)
{
return (int)tinfo.GetExecutor().ScalarUseModel(null, null,
//通过形参传递缓存策略对象:更改为不自动更新时间的
new SqlL2QueryCachePolicy
{
Expiry = new QueryCacheExpiryPolicy(span.Value, false)
});
}
else
{
return (int)tinfo.GetExecutor().Scalar();
}
}
更多的配置说明:
{
"name": "Person",
"sqls": {
"GetListL2Cache": {
"sql": "select * from ##tname",
"type": "query",
"policies": {
"l2cache": { //二级查询缓存,不设置缓存过期时间(缓存不过期)
}
}
},
"GetListL2Cache1": {
"sql": "select * from ##tname",
"type": "query",
"policies": {
"l2cache": {
"type": "query1" //指定CacheType,默认为query
}
}
},
"GetListL2Cache2": {
"sql": "select * from ##tname where 2=2",
"type": "query",
"policies": {
"l2cache": {
"expiry": {
"date": "2018-01-01" //指定缓存的过期日期
}
}
}
},
"GetListL2Cache3": {
"sql": "select * from ##tname where 3=3",
"type": "query",
"policies": {
"l2cache": {
"expiry": {
"span": "00:00:03" //指定缓存的过期间隔(换算日期为:当前时间 + 时间间隔),为了方便测试因此这里指定了3秒
}
}
}
},
"CountL2Cache": {
"sql": "select count(*) from ##tname",
"type": "scalar",
"policies": {
"l2cache": {
"expiry": {
"span": "00:00:03", //指定缓存的过期间隔(换算日期为:当前时间 + 时间间隔),为了方便测试因此这里指定了3秒
"isUpdateEach": true //是否每次获取缓存之后更新过期时间(这个属性 + span属性来进行模拟session访问更新过期时间)
}
}
}
}
}
}
二级缓存清理策略
配置:
{
"policies": {
//二级查询缓存清理策略
"clear": {
"isAsync": true,//是否异步进行清理
"isSelfAll": true, //是否清理 所在表下 的所有缓存
"tables": [ "Address" ], //需要进行缓存清理的表的名称(一般用于清理 其他表下 的所有查询缓存)
"cacheTypes": [ "query", "scalar1" ], //需要进行缓存清理的类型(用于清理 所在表下 的CacheType查询缓存)
"tableCacheTypes": { //需要进行缓存清理的类型(key为TableName,value为CacheType,一般用于清理 其他表下 的CacheType)
"Address": "query"
}
}
},
"sqls": {
"CountL2Cache": {
"sql": "select count(*) from ##tname",
"type": "scalar",
"policies": {
"l2cache": {
"type": "scalar1", //缓存的类型(Query默认为:query, Scalar默认为:scalar)
"expiry": {
"span": "00:00:03"
}
}
}
},
"AddPersonL2Cache": {
"sql": "insert into ##tname(name, birthday, addrid) values('tom_t2cache', '2018-1-1', 123) ",
"type": "nonquery",
"policies": {
"clear": {
"isSelfAll": true //是否清理 所在表下 的所有缓存
}
}
}
}
}
配置执行器调用:
public class PersonBLL
{
DBConfigTable tinfo;
public PersonBLL(DbContext db)
{
tinfo = db.GetConfigTable<Person>();
}
public int CountL2Cache()
{
return (int)tinfo.GetExecutor().Scalar();
}
public int AddPersonL2Cache()
{
return tinfo.GetExecutor().NonQuery();
}
}
让EFCore更疯狂些的扩展类库(二):查询缓存、分部sql、表名替换的策略配置的更多相关文章
- 让EFCore更疯狂些的扩展类库(一):通过json文件配置sql语句
前言 EF通过linq和各种扩展方法,再加上实体模型,编写数据库的访问代码确实是优美.舒服,但是生成的sql不尽如意.性能低下,尤其是复杂些的逻辑关系,最终大家还是会回归自然,选择能够友好执行sql语 ...
- 让时间处理简单化 【第三方扩展类库org.apache.commons.lang.time】
JAVA的时间日期处理一直是一个比较复杂的问题,大多数程序员都不能很轻松的来处理这些问题.首先Java中关于时间的类,从 JDK 1.1 开始,Date的作用很有限,相应的功能已由Calendar与D ...
- Z.ExtensionMethods 扩展类库
Z.ExtensionMethods 一个强大的开源扩展库 今天有意的在博客园里面搜索了一下 Z.ExtensionMethods 这个扩展类库,确发现只搜到跟这个真正相关的才两篇博文而已,我都点进去 ...
- (转)Entity Framework Extended Library (EF扩展类库,支持批量更新、删除、合并多个查询等)
转自:http://www.cnblogs.com/jinzhao/archive/2013/05/31/3108755.html 今天乍一看,园子里居然没有关于这个类库的文章,实在是意外毕竟已经有很 ...
- 怎么让dedecms生成html页面更快些
如何让织梦生成html页面更快些呢? 1.把文章模板里的“相关文章”.“热点文章”.“推荐文章”这类的标记删除了,用其它方式,如:shtml.js 引入 2.把织梦模板里用标记表示的模板路径.php附 ...
- EFCore扩展:IQueryable(linq)或sql执行的查询缓存与清理
前言 上一篇讲述了执行sql和配置的一些功能,这篇说明IQueryable(linq)或执行sql的查询缓存与清理,包括扩展到将缓存存储到Redis中. 扩展类库源码: github:https:// ...
- 【转】Entity Framework Extended Library (EF扩展类库,支持批量更新、删除、合并多个查询等)
E文好的可以直接看https://github.com/loresoft/EntityFramework.Extended 也可以在nuget上直接安装这个包,它的说明有点过时了,最新版本已经改用对I ...
- thinkphp5.1 使用第三方扩展类库
此案例介绍的不是通过composer加载的,是手工下载放入extend目录下的扩展类库,仍然以phpspider为例 将owner888目录放入extend目录下,也可以直接将phpspider目录放 ...
- [原创][开源]SunnyUI.Net, C# .Net WinForm开源控件库、工具类库、扩展类库、多页面开发框架
SunnyUI.Net, 基于 C# .Net WinForm 开源控件库.工具类库.扩展类库.多页面开发框架 Blog: https://www.cnblogs.com/yhuse Gitee: h ...
随机推荐
- ecstore中kvstore之mongodb
mongodb安装 详细见 http://blog.csdn.net/motian06/article/details/17560067 mongodb扩展安装 详细见 http://blog.csd ...
- Delphi的指针(转)
源:http://blog.csdn.net/henreash/article/details/7368088 Pointers are like jumps, leading wildly from ...
- PAT (Advanced Level) 1029. Median (25)
scanf读入居然会超时...用了一下输入挂才AC... #include<cstdio> #include<cstring> #include<cmath> #i ...
- JQuery的方便之处——宽高设置、坐标值和滚动条+事件绑定机制
1.元素的宽高 可以通过css来进行设置,例如:$("元素").css({"宽度":"值","高度":"值&q ...
- (中等) POJ 3660 Cow Contest,Floyd。
Description N (1 ≤ N ≤ 100) cows, conveniently numbered 1..N, are participating in a programming con ...
- [iOS Animation]-CALayer 显示方式
寄宿图 图片胜过千言万语,界面抵得上千图片 ——Ben Shneiderman 我们在第一章『图层树』中介绍了CALayer类并创建了一个简单的有蓝色背景的图层.背景颜色还好啦,但是如果它仅仅是展现了 ...
- opencv图像特征检测之斑点检测
前面说过,图像特征点检测包括角点和斑点,今天来说说斑点,斑点是指二维图像中和周围颜色有颜色差异和灰度差异的区域,因为斑点代表的是一个区域,所以其相对于单纯的角点,具有更好的稳定性和更好的抗干扰能力. ...
- 22、手把手教你Extjs5(二十二)模块Form的自定义的设计[1]
下面开始设计和完成一个简单的Form的自定义过程.先准备数据,在ModuleModel.js中的data属性下面,加入自定义Form的参数定义,下面的代码中定义了一个新的属性tf_formScheme ...
- 如何在Ubuntu中使用Eclipse + CDT开发C/C++程序
在Ubuntu中安装Eclipse和CDT步骤如下: 1. 下载资源(都下载到/home/maxw/Download/Eclipse下) A. 下载JRE(Java Runtime Enviro ...
- STM32单片机图片解码
图片解码首先是最简单的bmp图片解码,关于bmp的结构可自行查阅,代码如下 #ifndef __BMPDECODE_H_ #define __BMPDECODE_H_ #include "f ...