NET的相关论述

 
 年少时,为啥不为本人的指望去感奋三回啊?纵使一败涂地,也不悔有那时少轻狂。感叹相当多,目前事情也超多,博客也少之甚少更新了,毕竟每一种人都急需为友好的生存去全力。

 
 如今在三个群里碰到一位说的话,在这里间不再赘言,大约意思就是谐和各样通晓各类懂,面试时各样装X各个吊,本人老实的求教了弹指间他,问她是或不是懂那一个事物的平底原理,是不是理解过底层源码,能或不能够根据实际景况改革源码,谁知被他嘲弄说装逼,说知识那么多不可能怎么样都看源码和驾驭原理吧。但是笔者只想说,那只是你和睦说自身理解,难道精晓的框架不应当精晓源码和原理吗?难道领悟正是只明白怎么总结的应用吗?难道是自己拉家常的章程不对?

 
 目前碰着一个难题,这就是有关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。第一个映射结果是三个强类型列表,而第2个映射结果是叁个动态目的列表。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(卡塔尔(英语:State of Qatar)方法的泛型方法,有7个参数,首个参数为IDbConnection扩展类,表示对IDbConnection接口进行扩充,该方法应用了可选参数,提高艺术的扩展性。在Query方法的落到实处中,有叁个CommandDefinition类,用来表示sql操作的首要方面。在这类下有二个GetInit(卡塔尔(英语:State of Qatar)方法。

   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字节。剖断基本性能设置不为空后,调用ILGenerator类的Emit方法,Emit(卡塔尔(英语:State of Qatar)将钦赐的吩咐放在指令流上,该情势选用三个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,对于原理和尾部源码深入解析基本没有,在这里边就用那篇博文引出大神对其精细入微的剖析。希望对我们有几许声援,也终于尽力了。

admin

网站地图xml地图