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。第贰个映射结果是三个强类型列表,而第一个映射结果是一个动态指标列表。ExecuteMapperCommand实行而且不回来结果集。全部几个主意都将参数接受为无名氏类,在那之中属性值映射到同名的SQL参数。

   Dapper.Net意在仅管理结果集到目的映射。它不管理对象期间的涉及,它不会自动生成别的项目标SQL查询。

二.Dapper.NET原理剖判:

   通过Dapper.NET的源码大家能够窥见其首纵然“分部方法和总部类”,有关于“总部方法和总局类”的知识能够看那篇博客:。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,对于原理和底部源码解析基本未有,在这里就用那篇博文引出大神对其完美的剖析。希望对咱们有某个援救,也终归尽力了。

本文由澳门新葡萄京所有网站发布于澳门新葡萄京所有网站,转载请注明出处:NET的相关论述

TAG标签:
Ctrl+D 将本页面保存为书签,全面了解最新资讯,方便快捷。