关于Dapper.NET的相关论述
年少时,为何不为自己的梦想去拼搏一次呢?纵使头破血流,也不悔有那年少轻狂。感慨很多,最近事情也很多,博客也很少更新了,毕竟每个人都需要为自己的生活去努力。
最近在一个群里遇到一个人说的话,在这里不再赘述,大概意思就是自己各种精通各种懂,面试时各种装逼各种吊,本人真诚的求教了一下他,问他是否懂这些东西的底层原理,是否了解过底层源码,能否根据实际情况修改源码,谁知被他吐槽说装逼,说知识那么多不能什么都看源码和理解原理吧。但是我只想说,这可是你自己说自己精通,难道精通的框架不该了解源码和原理吗?难道精通就是只知道怎么简单的应用吗?难道是我聊天的方式不对?
最近遇到一个问题,那就是有关Dapper.NET的一些问题,Dapper.NET的效率为何很高?该组件的运行原理是什么?说句实话,我找了很久都没有发现类似的文章,不知道是不是我的搜素方式不对,还希望发现类似好的文章的朋友发给我看看,知识在于分享嘛,不要吝啬你的知识,让我们一起进步吧。
在这里简单介绍一下其原理
一.Dapper.NET概述:
项目开发时,我们都是需要考虑项目的技术架构,尤其是对数据库底层的考虑比较多。现在对于数据库的访问有ADO.NET,EF,Dapper.NET等等,不同的情况会有不同的选择,讨论的时候都会说到“xx很牛逼,xx效率很高”等等,总之需要干一场,才算我们开过会。(很多时候,在开会前项目选什么技术早就定了,但是不开个会就显得做事不严谨...),在选用Dapper.NET时,有人说到Dapper.NET效率高,很牛逼,也不知道那个新人说了一句“为什么Dapper.NET效率高?”
好尴尬...
Dapper.NET是一个简单的ORM,专门从SQL查询结果中快速生成对象。Dapper.Net支持执行sql查询并将其结果映射到强类型列表或动态对象列表。Dapper.Net缓存每个查询的信息。这种全面的缓存有助于从大约两倍于LINQ到SQL的查询生成对象。当前缓存由两个ConcurrentDictionary对象处理,它们从不被清除。
Dapper.Net通过扩展方法将两个映射函数添加到IDbConnection接口,这两个函数都命名为ExecuteMapperQuery。第一个映射结果是一个强类型列表,而第二个映射结果是一个动态对象列表。ExecuteMapperCommand执行并且不返回结果集。所有三个方法都将参数接受为匿名类,其中属性值映射到同名的SQL参数。
Dapper.Net旨在仅处理结果集到对象映射。它不处理对象之间的关系,它不会自动生成任何类型的SQL查询。
二.Dapper.NET原理浅析:
通过Dapper.NET的源码我们可以发现其主要是“分部方法和分部类”,有关于“分部方法和分部类”的知识可以看这篇博客:http://www.cnblogs.com/pengze0902/p/6369541.html。Dapper.Net也假定连接已打开并准备就绪,Dapper.NET通过对IDbConnection接口进行扩展。在Dapper.NET对数据库连接完成后,可以进行相关的操作,接下来我们就来看一下这些操作的实现方式。
1.Query()方法:
Query<T>(this IDbConnection cnn, string sql, object param = null, IDbTransaction transaction = null, bool buffered = true, int? commandTimeout = null, CommandType? commandType = null
改方法表示执行查询,返回按T输入的数据。该方法是Query()方法的泛型方法,有7个参数,第一个参数为IDbConnection扩展类,表示对IDbConnection接口进行扩展,该方法使用了可选参数,提高方法的扩展性。在Query方法的实现中,有一个CommandDefinition类,用来表示sql操作的关键方面。在该类下有一个GetInit()方法。
2.GetInit()方法:
我们都知道Dapper.NET通过Emit反射IDataReader的序列队列,来快速的得到和产生对象。GetInit()方法是一个静态方法,该方法的“Type commandType”参数表示连接关联的Command对象,返回一个Action<IDbCommand>委托。
我们就具体看一下是如何通过Emit反射IDataReader的序列队列的。
if (SqlMapper.Link<Type, Action<IDbCommand>>.TryGet(commandInitCache, commandType, out action)){ return action; }
Link<TKey, TValue>是一个泛型分部类,这是一个微缓存,查看是否存在一个Action<IDbCommand>的委托。
var bindByName = GetBasicPropertySetter(commandType, "BindByName", typeof(bool));var initialLongFetchSize = GetBasicPropertySetter(commandType, "InitialLONGFetchSize", typeof(int));
以上两个操作主要获取BindByName和InitialLONGFetchSize的获取基本属性设置。
if (bindByName != null || initialLongFetchSize != null)
{
var method = new DynamicMethod(commandType.Name + "_init", null, new Type[] { typeof(IDbCommand) });
var il = method.GetILGenerator();
if (bindByName != null)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, commandType);
il.Emit(OpCodes.Ldc_I4_1);
il.EmitCall(OpCodes.Callvirt, bindByName, null);
}
if (initialLongFetchSize != null)
{
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Castclass, commandType);
il.Emit(OpCodes.Ldc_I4_M1);
il.EmitCall(OpCodes.Callvirt, initialLongFetchSize, null);
}
il.Emit(OpCodes.Ret);
action = (Action<IDbCommand>)method.CreateDelegate(typeof(Action<IDbCommand>));
}
这一步是该操作的核心部分,利用Emit反射操作。根据上一步获取的对应名称的基本属性设置,采用DynamicMethod对象,定义和表示一个可以编译,执行和丢弃的动态方法。丢弃的方法可用于垃圾回收。调用该对象的GetILGenerator方法,返回方法的Microsoft中间语言(MSIL)生成器,默认的MSIL流大小为64字节。判断基本属性设置不为空后,调用ILGenerator类的Emit方法,Emit()将指定的指令放在指令流上,该方法接收一个IL流。EmitCall()将 call 或 callvirt 指令置于 Microsoft 中间语言 (MSIL) 流,以调用varargs 方法。我们看到OpCodes类,该类描述中间语言 (IL) 指令。CreateDelegate()完成动态方法并创建一个可用于执行它的委托。
通过以上的反射操作构建好对象后,就会接着执行对应的数据库操作。
3.QueryImpl():
private static IEnumerable<T> QueryImpl<T>(this IDbConnection cnn, CommandDefinition command, Type effectiveType)
{
object param = command.Parameters;
var identity = new Identity(command.CommandText, command.CommandType, cnn, effectiveType, param == null ? null : param.GetType(), null);
var info = GetCacheInfo(identity, param, command.AddToCache);
IDbCommand cmd = null;
IDataReader reader = null;
bool wasClosed = cnn.State == ConnectionState.Closed;
try
{
cmd = command.SetupCommand(cnn, info.ParamReader);
if (wasClosed) cnn.Open();
reader = cmd.ExecuteReader(wasClosed ? CommandBehavior.CloseConnection | CommandBehavior.SequentialAccess : CommandBehavior.SequentialAccess);
wasClosed = false;
var tuple = info.Deserializer;
int hash = GetColumnHash(reader);
if (tuple.Func == null || tuple.Hash != hash)
{
if (reader.FieldCount == 0)
yield break;
tuple = info.Deserializer = new DeserializerState(hash, GetDeserializer(effectiveType, reader, 0, -1, false));
if (command.AddToCache) SetQueryCache(identity, info);
}
var func = tuple.Func;
var convertToType = Nullable.GetUnderlyingType(effectiveType) ?? effectiveType;
while (reader.Read())
{
object val = func(reader);
if (val == null || val is T)
{
yield return (T)val;
}
else
{
yield return (T)Convert.ChangeType(val, convertToType, CultureInfo.InvariantCulture);
}
}
while (reader.NextResult()) { }
reader.Dispose();
reader = null;
command.OnCompleted();
}
finally
{
if (reader != null)
{
if (!reader.IsClosed) try { cmd.Cancel(); }
catch { /* don't spoil the existing exception */ }
reader.Dispose();
}
if (wasClosed) cnn.Close();
if (cmd != null) cmd.Dispose();
}
}
该方法为执行查询操作的核心方法,通过CommandDefinition类的相关操作后,获取到相应的对象后,执行这一步操作。该方法是IDbConnection的扩展方法,CommandDefinition表示sql的相关操作对象,Type表示传入的一个有效的类型。Identity对象表示Dapper中的缓存查询的标识,该类是一个分部类,可以对其进行相应的扩展。GetCacheInfo()获取缓存信息。
三.Dapper.NET扩展:
这一部分是借花献佛,该部分代码是对Dapper.NET代码做一封装,可以类似于操作其他ORM的方式,需要者可以自取,就不要到处去找这些东西了。
Dapper.NET扩展方法包
Dapper包
四.总结:
这篇博文是我硬着头皮写的,因为基本没有类似的文章,连参考的资料都没有,最多的就是调用代码的demo,对于原理和底层源码解析基本没有,在这里就用这篇博文引出大神对其全面的解析。希望对大家有一点帮助,也算是尽力了。
原文地址:http://www.cnblogs.com/pengze0902/p/6523458.html
.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注
赞赏
关于Dapper.NET的相关论述相关推荐
- 职业教育利益相关者的相关论述及研究不足
一.引言 2014 年 6 月 26 日,教育部等有关部门在国务院新闻办公室举行的新闻发布会上介绍了全国职业教育工作会议和<国务院关于加快发展现代职业教育的决定>的有关情况,教育部副部长鲁 ...
- Open Source
资源来源于http://www.cnblogs.com/Leo_wl/category/246424.html RabbitMQ 安装与使用 摘要: RabbitMQ 安装与使用 前言 吃多了拉就是队 ...
- Mysql非安装版的安装使用相关问题
一 解压 解压后如下: 二 新建my.ini my.ini [mysql] # 设置mysql客户端默认字符集 default-character-set=utf8 [mysqld] #设置3306端 ...
- .NET MVC5+ Dapper+扩展+AutoFac自动注入实现
1.首先创建一个MVC项目 定义Model 层 view 层 index.cshtml 控制器层Controllers等文件 2.在线安装或者引用dapper 以及扩展相关包 同时Autofac ...
- html中select标签默认选择,HTML中的select标签如何设置默认选中的选项
方法有两种. 第一种通过的属性来设置选中项,此方法可以在动态语言如php在后台根据需要控制输出结果. 1 2 3 4 5 1 option > 2 option > 3 option &g ...
- adobe怎么统计字数_本科毕业论文怎么写(正文写作要点精华)
毕业论文的写作过程包括,选题.找资料.做开题.列提纲.写正文.修改定稿等环节.要想知道本科毕业论文怎么写,我们就需要分别从这几个方面进行全面了解,由于,本栏目其他文章已经对论文选题.开题报告.论文提纲 ...
- 理解与理论:人工智能基础问题的悲观与乐观
来源:筑土为坛 梅剑华,男,1980年生,湖北秭归人,山西大学哲学社会学院教授,博士生导师,先后赴美国罗格斯大学.匹兹堡大学.奥地利萨尔茨堡大学等访学,研究方向是语言哲学与心灵哲学.实验哲学与认知科学 ...
- hql 语法与详细解释转
HQL查询 HQL查询: Criteria查询对查询条件进行了面向对象封装,符合编程人员的思维方式,不过HQL(Hibernate Query Lanaguage)查询提供了更加丰富的和灵活的查询特性 ...
- 驳斥《沙盒用于数据防泄密是重大技术原理性失误》
驳斥<沙盒用于数据防泄密是重大技术原理性失误> 最近网上出现了一篇名为<沙盒用于数据防泄密是重大技术原理性失误>的文章,经作者鉴定,是某不良公司***技术领先的竞争对手苏州深信 ...
最新文章
- R语言使用caret包对GBM模型自定义参数调优:自定义参数优化网格
- clickhouse 同步mysql_ClickHouse和他的朋友们(9)MySQL实时复制与实现
- python序列类型-Python内置的序列类型
- 【LeetCode】LeetCode之乘积为正数的最长子数组长度——暴力枚举+动态规划+Kadane算法
- 最近吸收的html CSS 知识
- Java概述、环境变量、注释、关键字、标识符、常量
- Git笔记(2) 入门认知
- keras faster物体检测_全网 | 深度学习目标检测算法(精选12篇)
- select 与case 以及函数练习
- jquery库实现iframe自适应内容高度和宽度
- 极速office(Excel)怎么把边框线条加粗
- html5 盒子阴影效果,如何制作平滑的“box-shadow”盒子阴影动画效果
- 使用 Swift 语言编程的优缺点
- 招聘路径规划算法工程师岗位
- C#小型书店管理系统
- Linux 监听进程状态
- 微信小程序之知乎日报
- 操作系统导论OSTEP 第七章作业答案 进程调度:介绍
- 机房UPS主机及电池该如何搬迁
- linux shell 中 %% *的含义