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反射IDataReader的序列队列的。

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反射IDataReader的行列队列的。

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代码做一封装,可以接近于操作其余ORM的办法,需求者可以自取,就不用四处去找那一个事物了。

 
 Dapper.NET扩充方法包

    Dapper包

三.Dapper.NET扩展:

 
 这一局地是顺手人情,该部分代码是对Dapper.NET代码做一封装,可以接近于操作其余ORM的法子,要求者可以自取,就无须到处去找这几个事物了。

 
 Dapper.NET增加方法包

    Dapper包

四.总结:

   
那篇博文是自个儿硬着头皮写的,因为基本没有像样的篇章,连参考的材料都未曾,最多的就是调用代码的demo,对于原理和底部源码解析基本没有,在此处就用那篇博文引出大神对其周密的分析。希望对我们有一些支持,也算是尽力了。

四.总结:

   
那篇博文是自己硬着头皮写的,因为基本没有类似的著作,连参考的资料都没有,最多的就是调用代码的demo,对于原理和底部源码解析基本没有,在此地就用那篇博文引出大神对其完善的剖析。希望对大家有几许扶植,也好不简单尽力了。