NET的有关论述

 
 年少时,为啥不为自身的冀望去振奋三次啊?纵使节节败退,也不悔有那个时候少轻狂。感叹非常多,前段时间业务也非常多,博客也少之甚少更新了,毕竟每一个人都需求为和睦的生存去全力。

 
 这段时间在叁个群里遇到一人说的话,在这里间不再赘述,大致敬思正是投机各样精晓各样懂,面试时各类装B各个吊,本人赤诚的求教了须臾间她,问她是或不是懂那么些事物的平底原理,是还是不是了然过底层源码,能或不能依照实际境况改善源码,什么人知被他调侃说装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个参数,第1个参数为IDbConnection扩大类,表示对IDbConnection接口进行扩大,该办法运用了可选参数,升高措施的扩大性。在Query方法的得以达成中,有三个CommandDefinition类,用来代表sql操作的主要方面。在这里类下有一个GetInit(卡塔尔方法。

   2.GetInit()方法:

   
大家都晓得Dapper.NET通过Emit反射IDataReader的行列队列,来急速的获取和发生对象。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的得到Kit质量设置。

    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(卡塔尔(英语:State of Qatar)获取缓存消息。

三.Dapper.NET扩展:

 
 那黄金年代某个是借花献佛,该片段代码是对Dapper.NET代码做大器晚成封装,能够贴近于操作别的ORM的不二等秘书籍,须要者能够自取,就绝不随地去找这么些东西了。

 
 Dapper.NET增添方法包

    Dapper包

四.总结:

   
那篇博文是自家硬着头皮写的,因为基本未有看似的文章,连参谋的资料都并未有,最多的就是调用代码的demo,对于原理和尾部源码拆解解析基本未有,在这里边就用那篇博文引出大神对其完美的分析。希望对我们有有些助手,也究竟尽力了。

相关文章