难道说领悟的框架不应该领会源码和规律吗公海赌船710

 
 年少时,为什么不为本人的指望去拼搏一遍啊?纵使人仰马翻,也不悔有那一年少轻狂。感叹比很多,近年来工作也非常多,博客也相当少更新了,究竟每一种人都急需为温馨的生活去努力。

 
 近期在三个群里境遇一位说的话,在此处不再赘述,大概意思正是和睦各个驾驭种种懂,面试时各类装X种种吊,自己真诚的求教了一晃她,问他是还是不是懂那一个事物的最底层原理,是不是通晓过底层源码,能不可能依据实际情形修改源码,哪个人知被她戏弄说装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公海赌船710,指标管理,它们从不被扫除。

 
 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反射IData里德r的类别队列,来飞快的收获和发生对象。GetInit()方法是三个静态方法,该措施的“Type
commandType”参数表示连接关联的Command对象,再次来到一个Action<IDbCommand>委托。

   咱们就具体看一下是怎样通过Emit反射IData里德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代码做一封装,能够附近于操作其余ORM的措施,要求者能够自取,就毫无处处去找那么些东西了。

 
 Dapper.NET增加方法包

    Dapper包

四.总结:

   
那篇博文是自个儿硬着头皮写的,因为基本未有看似的稿子,连参照他事他说加以考察的资料都未曾,最多的便是调用代码的demo,对于原理和尾巴部分源码深入分析基本未有,在那边就用这篇博文引出大神对其体贴入微的分析。希望对大家有少数协理,也算是尽力了。

相关文章