NET的有关论述

 
 年少时,为什么不为自身的想望去振作三遍啊?纵使一败涂地,也不悔有那一年少轻狂。感慨诸多,这两天业务也好些个,博客也非常少更新了,毕竟每一种人都亟待为和睦的生存去全力。

 
 方今在壹个群里遭遇一个人说的话,在这里不再赘述,差不离意思正是自个儿各样领会各个懂,面试时各类装逼各个吊,自己真诚的求教了一下她,问她是否懂这几个事物的底层原理,是或不是精晓过底层源码,能还是不可能依照真实景况修改源码,何人知被他嘲弄说装逼,说知识那么多不能够怎么着都看源码和清楚原理吧。可是自个儿只想说,那只是您本身说本人精晓,难道通晓的框架不应当领悟源码和原理吗?难道精晓就是只精通怎么回顾的施用吗?难道是自身拉家常的措施不对?

 
 近期高出二个主题材料,这正是有关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,
电视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,对于原理和尾巴部分源码深入分析基本未有,在此处就用那篇博文引出大神对其无微不至的解析。希望对大家有点扶助,也究竟尽力了。