关于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跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326486.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数年之前的寒假

版权声明&#xff1a;文章可以随便转载&#xff0c;但是转载时带上原文地址来源&#xff0c;侵权必究 https://blog.csdn.net/qq_34137397/article/details/54882702对于上学的孩子来说每年都有寒假&#xff0c;可是一样的寒假总是不一样的玩法。自从高中毕业之后&#xff0c;很…

js object 常用方法总结

转载自 js object 常用方法总结 Object.assign(target,source1,source2,...) 该方法主要用于对象的合并&#xff0c;将源对象source的所有可枚举属性合并到目标对象target上,此方法只拷贝源对象的自身属性&#xff0c;不拷贝继承的属性。 Object.assign方法实行的是浅拷贝&…

发布 ASP.NET Core 应用

第一步&#xff1a;运行 dotnet restore 命令&#xff0c;以还原项目中指定的依赖项 1 dotnet restore 第二步&#xff1a;使用 dotnet build 命令为目标平台上的应用创建调试版本。 如果不指定想要生成的运行时标识符&#xff0c;则 dotnet build 命令将会创建仅适用于当前系统…

继承类对方法的影响java_4-Java面向对象-继承(上)

什么是继承?继承有哪些特点?我们在Java中如何实现继承?程序中的继承(面向对象编程思想来源于生活):解决重复代码的出现问题。抽取共性生成父类。此时猫和狗直接继承父类将可以直接使用父类的这些成员属性和方法。此时子类当中的方法就可以只写子类所特有的东西。特点: 1. 利…

javaSE基础代码案例

package org.test; import java.util.Arrays; import java.util.Scanner;/*** * 项目名称&#xff1a;Test * 类名称&#xff1a;TestMain * 类描述&#xff1a; * 创建人&#xff1a;Mu Xiongxiong * 创建时间&#xff1a;2018-3-29 下午3:49:00 * 修改人&…

迪杰斯特拉算法(最短路径)

描述 算法过程 代码实现 package com.atguigu.dijkstra;import com.sun.xml.internal.fastinfoset.algorithm.BooleanEncodingAlgorithm;import javax.sound.midi.Soundbank; import java.util.Arrays; import java.util.TimerTask;public class DijkstraAlgorithm {public st…

MySQL instr()函数

转载自 MySQL instr()函数 MySQL INSTR函数简介 有时&#xff0c;您想要在字符串中查找子字符串或检查字符串中是否存在子字符串。在这种情况下&#xff0c;您可以使用字符串内置INSTR()函数。 INSTR()函数返回字符串中子字符串第一次出现的位置。如果在str中找不到子字符串…

如何给视频中插入视频,字幕,以及去掉前后广告

昨天白天接到了一个这样的需求&#xff0c;就是剪辑一段视频&#xff0c;给视频中加入插入一个剪短的介绍&#xff0c;然后把没有用的截取掉。 看起来很简单&#xff0c;确实&#xff0c;利用常用的视频剪辑软件就可以直接实现&#xff0c;但是事实并不是这样的&#xff0c;接…

ZKEACMS for .Net Core 深度解析

ZKEACMS 简介 ZKEACMS.Core 是基于 .Net Core MVC 开发的开源CMS。ZKEACMS可以让用户自由规划页面布局&#xff0c;使用可视化编辑设计“所见即所得”&#xff0c;直接在页面上进行拖放添加内容。 ZKEACMS使用插件式设计&#xff0c;模块分离&#xff0c;通过横向扩展来丰富CMS…

java design按钮_DesignJava 设计模式,讲述 的各种 方便在项目中进行 框架结构 Develop 238万源代码下载- www.pudn.com...

文件名称: DesignJava下载收藏√ [5 4 3 2 1 ]开发工具: Java文件大小: 1675 KB上传时间: 2013-11-21下载次数: 2提 供 者: 102426详细说明&#xff1a;JAVA设计模式&#xff0c;讲述java的各种设计模式&#xff0c;方便在项目中进行设计框架结构-JAVA design patterns, j…

剪辑视频、去掉爱剪辑前后广告、视频中添加黑幕简要教程

昨天白天接到了一个这样的需求&#xff0c;就是剪辑一段视频&#xff0c;给视频中加入插入一个剪短的介绍&#xff0c;然后把没有用的截取掉。看起来很简单&#xff0c;确实&#xff0c;利用常用的视频剪辑软件就可以直接实现&#xff0c;但是事实并不是这样的&#xff0c;接下…

弗洛伊德算法

思路分析 代码实现 package com.atguigu.floyd;import java.util.Arrays;public class FloydAlgorithm {public static void main(String[] args) {//测试看看图是否创建成功char[] vertex{A,B,C,D,E,F,G};//创建邻接矩阵int[][] matrixnew int[vertex.length][vertex.length]…

Productivity Power Tools,对于Visual Studio 2017的15个扩展

在Visual Studio 2017正式发布期间&#xff0c;微软公司更新并发布了Productivity Power Tools的扩展版本。Productivity Power Tools的这个版本包括了针对VS 2017的15处扩展。 新版本Productivity Power Tools的优点之一是它允许微软监测哪些组件是开发者最频繁使用的&#xf…

常用数据库复习资料

mast&#xff1a;数据库控制SQL Server的所有方面。这个数据库中包括所有的配置信息、用户登录信息、当前正在服务器中运行的过程的信息。model:数据库是建立所有用户数据库时的模板。当你建立一个新数据库时&#xff0c;SQL Server会把model数据库中的所有对象建立一份拷贝并移…

利用 Azure Functions 实现无服务器体系结构

从工具到机器再到计算机&#xff0c;我们一直在寻找能够自动执行重复工作并让我们所处理的上下文规范化的方法&#xff0c;以便我们可以将重心放在做出高价值的专业化贡献上&#xff0c;从而完成任务并解决问题。 与此同时&#xff0c;很显然&#xff0c;随着 IT 产业的不断发展…

2020蓝桥杯省赛---java---C---3( 跑步训练)

题目描述 代码实现 方式一 方式二 package com.atguigu.lanqiao;public class Main {public static void main(String[] args) {int target10000;int count0;boolean flagtrue;//判断此次是否需要跑步while (true){//如果小于600体力并且需要跑步&#xff0c;证明这一分钟跑…

sqlserver中常用的几个存储过程

sqlserver中的存储过程&#xff0c;何为存储过程呢&#xff1f; 存储过程&#xff08;Stored Procedure&#xff09;是在大型数据库系统中&#xff0c;一组为了完成特定功能的SQL 语句集&#xff0c;存储在数据库中&#xff0c;经过第一次编译后再次调用不需要再次编译&#x…

java枚举类定义性别_Java 枚举类和自定义枚举类和enum声明及实现接口的操作

1.枚举类注&#xff1a;JDK1.5之前需要自定义枚举类JDK 1.5 新增的 enum 关键字用于定义枚举类若枚举只有一个成员, 则可以作为一种单例模式的实现方式1.枚举类的属性1、枚举类对象的属性不应允许被改动, 所以应该使用 private final 修饰2、枚举类的使用 private final 修饰的…

2020蓝桥杯省赛---java---B---4( 合并检测)

题目描述 思路分析 假设A国有n个人&#xff0c;感染者有n/100 每k个人一组&#xff0c;共n/k组&#xff0c;共用n/k瓶试剂 按照最坏的情况&#xff0c;每多出一个感染者就多用k瓶试剂&#xff0c; 因此共用n/k(n/100)*k瓶试剂 n是定值&#xff0c;所以求(1/kk/100)最小 由于ab…

visual studio 2017发布dotnet core到docker

docker的好处不用多说&#xff0c;有不了解的可移步《docker入门》&#xff0c;作为一个.net方面的老鸟也想早点搭上docker末班车&#xff0c;减少布署中的各种坑。以下我是在Visual Studio 2017正式版发布后&#xff08;其实VS2015也是可以的&#xff09;&#xff0c;完全跑起…