说知识那么多不可能怎么样都看源码和清楚原理吧

 
 年少时,为什么不为自身的梦想去拼搏一遍啊?纵使一败涂地,也不悔有那个时候少轻狂。感慨比相当多,近年来作业也相当多,博客也非常少更新了,毕竟每个人都亟待为和谐的生活去全力。

 
 这段日子在贰个群里碰着一人说的话,在这里地不再赘言,大致敬思正是戮力同心各个理解种种懂,面试时各样夸口各个吊,自身真诚的求教了一下他,问她是还是不是懂那个事物的底层原理,是还是不是通晓过底层源码,能还是不能够依照真实情状修改源码,什么人知被她调侃说装B,说知识那么多不能如何都看源码和透亮原理吧。不过自身只想说,那可是你协和说自身精晓,难道掌握的框架不应当驾驭源码和公理吗?难道通晓就是只领悟怎么归纳的使用吗?难道是自家聊天的法子不对?

 
 目前蒙受一个标题,那正是有关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,
电视机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包

四.总结:

   
这篇博文是自己硬着头皮写的,因为基本未有看似的篇章,连参考的素材都不曾,最多的就是调用代码的demo,对于原理和尾巴部分源码深入分析基本没有,在那处就用这篇博文引出大神对其完美的分析。希望对我们有少数声援,也总算尽力了。

相关文章