有关Dapper.NET的连锁论述。关于Dapper.NET的系论述。

by admin on 2018年10月5日

 
 年少时,为何非呢温馨的期望去拼搏一糟也?纵使头破血流,也不悔有那么年少好狂。感慨大多,最近作业也深多,博客也深少更新了,毕竟每个人还得吗好的生存失去拼命。

 
 年少时,为何非呢和谐之要去拼搏一不成为?纵使头破血流,也不悔有那年少好狂。感慨很多,最近作业吗格外多,博客也十分少更新了,毕竟每个人且亟需也温馨的活失去全力。

 
 最近当一个群里遇到一个总人口说之说话,在这里不再赘言,大概意思就是是投机各种会各种懂,面试时各种装逼各种吊,本人真诚之求教了一下异,问他是不是知情这些东西的根原理,是否了解过根源码,能否根据实际情形修改源码,谁知被他吐槽说装逼,说知识那么基本上无克啊还扣留源码和喻原理吧。但是自独自想说,这只是你协调说自己会,难道会的框架不拖欠了解源码和公理为?难道会就是仅仅晓得怎么概括的使为?难道是本身拉家常的法不对?

 
 最近以一个群里遇到一个人数说的讲话,在这里不再赘述,大概意思就是是自己各种会各种懂,面试时各种装逼各种吊,本人真诚之求教了一下异,问他是否知晓这些东西的根原理,是否了解过根源码,能否根据实际情形修改源码,谁知被他吐槽说装逼,说知识那么基本上不能够呀还扣留源码和了解原理吧。但是自偏偏想说,这可你协调说好精通,难道会的框架不该了解源码和公理为?难道会就是一味掌握怎么概括的运用为?难道是自家拉的办法不对?

 
 最近遇见一个题材,那就算是关于Dapper.NET的片题目,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概述:

 
项目开时,我们且是索要考虑项目之技能架构,尤其是本着数据库底层的设想比较多。现在对数据库的访有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的源码我们得以窥见那重要是“分部方法及分部类”,有关于“分部方法以及分部类”的学识可以拘留这首博客: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包

三.Dapper.NET扩展:

 
 这同片段是借花献佛,该片段代码是对准Dapper.NET代码做相同封装,可以接近于操作其他ORM的章程,需要者可以自取,就绝不到处去寻觅这些东西了。

 
 Dapper.NET扩展方法包

    Dapper包

四.总结:

   
这篇博文是本身强项在头皮写的,因为基本无类似之章,连参考的资料还未曾,最多之就算是调用代码的demo,对于原理和底部源码解析基本没,在此间就是用就首博文引出大神对其无微不至的解析。希望对大家产生一些助,也终究尽力了。

四.总结:

   
这首博文是我强项在头皮写的,因为基本没看似的篇章,连参考的材料都没有,最多之哪怕是调用代码的demo,对于原理同底源码解析基本没,在此处就就此就首博文引出大神对该完善的解析。希望对大家来某些辅助,也终于尽力了。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图