NET的相干论述

by admin on 2019年10月20日

 
 年少时,为什么不为自个儿的梦想去奋不以为意贰次啊?纵使瓦解土崩,也不悔有那个时候少轻狂。感叹非常多,前段时间事务也比较多,博客也很少更新了,毕竟每种人都急需为温馨的活着去拼命。

 
 近日在一个群里境遇壹人说的话,在此不再赘述,大致意思就是本身各样明白各类懂,面试时种种吹嘘各个吊,本身真诚的求教了风姿浪漫晃她,问她是还是不是懂这个事物的底层原理,是或不是驾驭过底层源码,能或不能够遵照实际意况修改源码,谁知被他戏弄说吹嘘,说知识那么多不能够怎么都看源码和清楚原理吧。但是作者只想说,那可是您自个儿说自身明白,难道精晓的框架不应当驾驭源码和原理吗?难道驾驭就是只通晓怎么总结的施用吗?难道是自己聊天的格局不对?

 
 如今蒙受八个主题材料,这正是有关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,
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字节。判定Kit品质设置不为空后,调用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,对于原理和尾部源码剖判基本未有,在那间就用那篇博文引出大神对其精细入微的深入分析。希望对大家有几许推搡,也算是尽力了。

相关文章

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图