NET的相关论述

by admin on 2019年5月20日

 
 年少时,为什么不为本人的想望去感奋贰次啊?纵使土崩瓦解,也不悔有那个时候少轻狂。感慨大多,方今业务也多数,博客也很少更新了,究竟各种人都亟需为自身的生存去全力。

 
 最近在3个群里遇到一位说的话,在此间不再赘言,大致意思就是投机种种精通各类懂,面试时各类吹嘘种种吊,自己真诚的求教了刹那间她,问她是或不是懂那个东西的平底原理,是不是领悟过底层源码,能不可能依据实际意况修改源码,哪个人知被他调侃说夸口,说知识那么多无法怎样都看源码和理解原理吧。可是本身只想说,那只是您自身说本人领会,难道领悟的框架不应当了然源码和法则吗?难道掌握就是只驾驭怎么总结的利用吗?难道是自身聊天的措施不对?

 
 近些日子遇上一个标题,那正是关于Dapper.NET的片段题目,Dapper.NET的成效为什么异常高?该零件的运作规律是如何?说句实话,小编找了很久都不曾意识类似的篇章,不知底是还是不是本人的搜素方式不对,还指望开掘类似好的文章的爱侣发给笔者看看,知识在于分享嘛,不要吝啬你的文化,让大家一同前行啊。

   在这里大概介绍一下其规律  

一.Dapper.NET概述:

 
项目支付时,大家都是要求驰念项目标本事框架结构,非常是对数据库底层的设想相比多。今后对此数据库的拜会有ADO.NET,EF,Dapper.NET等等,分化的动静会有两样的接纳,研商的时候都会聊起“xx很牛逼,xx功能相当高”等等,总之须求干一场,才算大家开过会。(繁多时候,在开会前项目选什么样手艺1度定了,可是不开个会就展现做事不严刻…),在选取Dapper.NET时,有一些人聊到Dapper.NET效能高,很牛逼,也不亮堂非常新人说了一句“为什么Dapper.NET效用高?”

   好尴尬…

   Dapper.NET是二个粗略的OEvoqueM,特意从SQL查询结果中高速转移对象。Dapper.Net帮忙推行sql查询并将其结果映射到强类型列表或动态目的列表。Dapper.Net缓存各类查询的新闻。这种周密的缓存有助于从轮廓上两倍于LINQ到SQL的询问生成对象。当前缓存由多个ConcurrentDictionary指标管理,它们未有被铲除。

 
 Dapper.Net通过增添方法将四个映射函数增加到IDbConnection接口,这八个函数都命名称叫ExecuteMapperQuery。第贰个映射结果是1个强类型列表,而第三个映射结果是贰个动态目的列表。ExecuteMapperCommand推行并且不回去结果集。全数四个艺术都将参数接受为佚名类,个中属性值映射到同名的SQL参数。

   Dapper.Net意在仅处理结果集到目的映射。它不管理目的之间的关联,它不会自动生成任何类型的SQL查询。

2.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个参数,第3个参数为IDbConnection增添类,表示对IDbConnection接口进行扩展,该办法应用了可选参数,提升措施的扩张性。在Query方法的落到实处中,有多个CommandDefinition类,用来代表sql操作的重要方面。在此类下有一个GetInit()方法。

   2.GetInit()方法:

   
大家都精通Dapper.NET通过Emit反射IDataReader的行列队列,来飞速的收获和发生对象。GetInit()方法是3个静态方法,该办法的“Type
commandType”参数表示连接关联的Command对象,重回三个Action<IDbCommand>委托。

   大家就现实看一下是何许通过Emit反射IDataReader的连串队列的。

if (SqlMapper.Link<Type, Action<IDbCommand>>.TryGet(commandInitCache, commandType, out action)){ return action; }

   Link<TKey,
电视alue>是二个泛型总部类,那是1个微缓存,查看是或不是留存二个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对象,定义和象征贰个方可编写翻译,实行和丢弃的动态方法。舍弃的不2秘技可用以垃圾回收。调用该指标的GetILGenerator方法,再次回到方法的Microsoft中间语言(MSIL)生成器,暗中认可的MSIL流大小为6四字节。剖断基脾品质设置不为空后,调用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中的缓存查询的标记,该类是3个分公司类,能够对其进展对应的增添。GetCacheInfo()获取缓存音信。

三.Dapper.NET扩展:

 
 这一片段是顺水人情,该部分代码是对Dapper.NET代码做壹封装,能够临近于操作其余O翼虎M的章程,须求者能够自取,就毫无随地去找那个事物了。

 
 Dapper.NET扩大方法包

    Dapper包

四.总结:

   
那篇博文是本人硬着头皮写的,因为基本未有像样的稿子,连参考的资料都不曾,最多的就是调用代码的demo,对于原理和尾部源码分析基本未有,在此处就用那篇博文引出大神对其无微不至的解析。希望对大家有一点助手,也算是尽力了。

发表评论

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

网站地图xml地图