NET的连锁论述,NET的连锁论述

 
 年少时,为什么不为自己的企盼去努力五回啊?纵使头破血流,也不悔有这年少轻狂。感慨很多,近期政工也很多,博客也很少更新了,毕竟每个人都需要为团结的生存去全力。

 
 年少时,为啥不为自己的期待去加油一回啊?纵使头破血流,也不悔有这年少轻狂。感慨很多,如今业务也很多,博客也很少更新了,毕竟每个人都亟需为温馨的生存去全力。

 
 近日在一个群里遭逢一个人说的话,在此处不再赘言,大概意思就是和谐各类精晓各个懂,面试时各类装逼各个吊,本人真诚的求教了一晃她,问她是否懂那多少个东西的底层原理,是否了解过底层源码,能否依据实际状况修改源码,何人知被他吐槽说装逼,说知识那么多无法如何都看源码和清楚原理吧。不过本人只想说,这可是你协调说自己领悟,难道了解的框架不该精通源码和原理吗?难道精晓就是只领会怎么概括的应用吗?难道是自家聊天的措施不对?

 
 目前在一个群里境遇一个人说的话,在这里不再赘言,大概意思就是协调各样了然各个懂,面试时各个装逼各样吊,本人真诚的求教了一晃他,问他是否懂这多少个东西的最底层原理,是否了然过底层源码,能否依照实际意况修改源码,何人知被她吐槽说装逼,说知识那么多不可能怎么着都看源码和清楚原理吧。但是自己只想说,这不过你协调说自己了然,难道精通的框架不该了解源码和规律吗?难道领悟就是只通晓怎么概括的运用吗?难道是自我拉家常的章程不对?

 
 近期遇上一个题材,这就是有关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反射IData里德(Reade)r的行列队列的。

if (SqlMapper.Link<Type, Action<IDbCommand>>.TryGet(commandInitCache, commandType, out action)){ return action; }

   Link<TKey,
电视alue>是一个泛型分部类,这是一个微缓存,查看是否留存一个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反射IData里德r的队列队列,来很快的拿走和发生对象。GetInit()方法是一个静态方法,该措施的“Type
commandType”参数表示连接关联的Command对象,重回一个Action<IDbCommand>委托。

   大家就现实看一下是哪些通过Emit反射IData里德(Reade)r的系列队列的。

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,对于原理和底部源码解析基本没有,在此地就用这篇博文引出大神对其完善的辨析。希望对我们有几许救助,也算是尽力了。

相关文章