Dapper源码学习和源码修改

之前ORM比较火热,自己也搞了个WangSql,但是感觉比较low,大家都说Dapper性能好,所以现在学习学习Dapper,下面简单从宏观层面讲讲我学习的Dapper。

再了解一个东西前,先得学会使用,我也不再赘述怎么使用,接转一个文章吧

http://www.cnblogs.com/yankliu-vip/p/4182892.html

好就当学习了吧,该去看看源码了,到底怎么实现和好在哪呢。

先上一张图,已经把SqlMapper.cs按类拆分了,同时我自己在学习过程中也删了加了改了一些类。

 

当然最重要的类还是SqlMapper.cs这个类,那就开始吧。

本来想把这个SqlMapper.cs类代码全部粘贴的发现太长了,就算了吧,就把一些关键代码粘贴过来。

private static CacheInfo GetCacheInfo(Identity identity)

        {

            CacheInfo info;

            if (!TryGetQueryCache(identity, out info))

            {

                info = new CacheInfo();

                if (identity.parametersType != null)

                {

                    if (typeof(string).IsAssignableFrom(identity.parametersType))

                    {

                        info.ParamReader = delegate(IDbCommand cmd, object obj) { (new StringParameters() as IDynamicParameters).AddParameters(cmd, identity, obj); };

                    }

                    else if (typeof(IDictionary).IsAssignableFrom(identity.parametersType))

                    {

                        info.ParamReader = delegate(IDbCommand cmd, object obj) { (new DictionaryParameters() as IDynamicParameters).AddParameters(cmd, identity, obj); };

                    }

                    else

                    {

                        info.ParamReader = CreateParamInfoGenerator(identity);

                    }

                }

                SetQueryCache(identity, info);

            }

            return info;

        }

来来来,划重点了 info.ParamReader = CreateParamInfoGenerator(identity); 看到没,这货是干嘛的啊,哪里用的呢?

就这里用的,其实就是那是一个委托,主要用来创建Command的DataParameter的,不信看下面

private static IDbCommand SetupCommand(IDbConnection cnn, IDbTransaction transaction, string sql, Action<IDbCommand, object> paramReader, object obj, int? commandTimeout, CommandType? commandType)

        {

            var cmd = cnn.CreateCommand();

            var bindByName = GetBindByName(cmd.GetType());

            if (bindByName != null) bindByName(cmd, true);

            cmd.Transaction = transaction;

            cmd.CommandText = FormatSql(sql);

            if (commandTimeout.HasValue)

                cmd.CommandTimeout = commandTimeout.Value;

            if (commandType.HasValue)

                cmd.CommandType = commandType.Value;

            if (paramReader != null)

            {

                paramReader(cmd, obj);

            }

            return cmd;

        }

又划重点了, paramReader(cmd, obj); 这里就是执行委托创建Command的DataParameter了。

如果有人问为什么要这个呢,那就是你上面连Dapper基本使用都没看啊,滚回去看看先。

举个例子:

sql = "insert into Teacher(Id,Name) values(@Id,@Name)";

                string tid = Guid.NewGuid().ToString();

                teacher = new Teacher()

                {

                    Id = tid,

                    Name = "wang"

                };

                intResult = SqlMapper.Execute(conn, sql, teacher);

这里 SqlMapper.Execute(conn, sql, teacher); 参数teacher就是上面 paramReader(cmd, obj);对应的参数obj,这个委托呢就是将自定义实体teacher变成cmd的Parameters。

那么你又要问了,怎么变的?额,这么嘛就是难点了....

回到上面看看,委托的创建 info.ParamReader = CreateParamInfoGenerator(identity); 

关键点也是难点啊同学们CreateParamInfoGenerator这个方法是干嘛的啊,就是创建委托的啊,你个白痴。


好了,方法给你了,自己看吧,注释写的多详细的啊。恩....

WTF,英文的啊,不要紧有翻译的,反正自己看吧,我来给你讲怕误人子弟啊。

就我删减后的Dapper 来说入参解析部分其实就到此结束,什么鬼,毫无亮点,要你讲有何用。

别急,别急,下面讲讲我修改部分。

使用中,我发现参数的这么写 insert into Student(Id,Name,Tid) values(@Id,@Name,@Tid) 那如果我换了数据库比如MySql又得改@为?,换成Oracle又得把@改成:,这是我不能忍受的其一。

使用中,我发现 sql = "delete from Student where Id=#Id#"; intResult = SqlMapper.Execute(conn, sql, "jkajskajsk"); 报错,为毛啊,连字符串入参传入你都不认识,这是我不能忍受其二。

以上问题,可能是我版本问题,我用的是Dapper NET2.0版本。

不管为什么,先解决这个两个痛点。

 

问题一:

原因分析,主要是不知道数据库类型造成的。

解决办法,那我就提前告诉你,数据库相关信息,我们采用一种驱动方式来设置数据库相关信息。

我新建了个类DbProvider.cs

    internal class DbProvider{        public bool UseParameterPrefixInSql { get; set; }      
public bool UseParameterPrefixInParameter { get; set; }
public string ParameterPrefix { get; set; }}

 

很简单,后期你可以自己扩展,  ParameterPrefix  这个就是数据库参数前缀,比如@ ? :

//dbProvider

            dbProvider = new DbProvider()

            {

                UseParameterPrefixInSql = true,

                UseParameterPrefixInParameter = true,

                ParameterPrefix = "@"

            };

在SqlMapper创建一个 dbProvider 构造函数里面 对其初始化,具体值最好写在web.config里面,初始化的时候去读配置文件。

有了这个之前的SQL我们可以改改了 insert into Student(Id,Name,Tid) values(#Id#,#Name#,#Tid#)当然原来的写法也是支持的,只不过现在这种写法,保证的SQL参数的统一性,以后切换数据库也容易多了。 

可是这样写了,能正常运行吗?答案是NO,所以还需要下面的方法。

//我写的

        internal static string FormatNameForSql(string parameterName)

        {

            return dbProvider.UseParameterPrefixInSql ? (dbProvider.ParameterPrefix + parameterName) : parameterName;

        }

        internal static string FormatNameForParameter(string parameterName)

        {

            return dbProvider.UseParameterPrefixInParameter ? (dbProvider.ParameterPrefix + parameterName) : parameterName;

        }

        internal static string FormatSql(string sql)

        {

            Regex regex = new Regex("#([a-zA-Z0-9_]+?)#", RegexOptions.IgnoreCase | RegexOptions.Multiline);

            var ms = regex.Matches(sql);

            foreach (Match item in ms)

            {

                sql = sql.Replace(item.Value, FormatNameForSql(item.Groups[1].Value));

            }

            return sql;

        }

主要是这个方法 FormatSql 什么时候调呢,在这里

好了,问题一,反正是解决了,下面看看问题二了。

 

问题二:

原因分析,

来来来,划重点了 info.ParamReader = CreateParamInfoGenerator(identity); 看到没,这货是干嘛的啊,哪里用的呢?

就这里用的,其实就是那是一个委托,主要用来创建Command的DataParameter的

引用的上面的,那个委托啊CreateParamInfoGenerator不支持String、Dictionary这种入参造成的。

解决办法,既然那个委托不支持,我就给不同的类型创建不同的委托就行了啥。

我为继承string类型的创建了一个委托,委托是执行StringParameters实例的AddParameters方法。

我为继承IDictionary类型的创建了一个委托,委托是执行DictionaryParameters实例的AddParameters方法。

通过不同的委托就能实现不同入参实现给Command的Parameters创建赋值了,哈哈哈哈哈....当然你要实现int double ...都一样的方法,加个类继承IDynamicParameters即可。

现在这样子都可以正常使用了

sql = "delete from Student where Id=#Id#";

                intResult = SqlMapper.Execute(conn, sql, "jkajskajsk");



                sql = "delete from Student where Id=#Id# and Name=@Name and Name=@Name1";

                Hashtable dic = new Hashtable();

                dic.Add("Id", "123");

                dic.Add("Name", "s1234");

                dic.Add("Name1", "d12345");

                intResult = SqlMapper.Execute(conn, sql, dic);

总结:

这篇文章只是对Dapper入参进行的分析,出参还没看呢,先这样吧,有空再说.

原文地址:http://www.cnblogs.com/deeround/p/6612213.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/326329.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

php批量评价,彻底杜绝 WordPress 批量垃圾评论留言的三步曲

本文将详细介绍如何采取三步曲彻底告别烦人的 WordPress 批量垃圾评论问题&#xff0c;还你一个干净清爽的后台评论区。刚开始使用 WordPress 程序建站的朋友们肯定或多或少都被其批量垃圾评论困扰过。然后大家就开始寻思解决的办法&#xff0c;找到的网上说法大都是 Akismet A…

MySQL sysdate()函数

转载自 MySQL sysdate()函数 MySQL SYSDATE函数介绍 下面说明了SYSDATE()函数的语法&#xff1a; SYSDATE(fsp);如果函数用于字符串上下文或YYYYMMDDHHMMSS格式&#xff0c;则SYSDATE()函数将返回当前日期时间&#xff0c;格式为“YYYY-MM-DD HH:MM:SS”的值&#xff0c;以…

2018蓝桥杯省赛---java---C---2(猴子分香蕉)

题目描述 思路分析 直接采用暴力破解&#xff0c;先限定范围&#xff0c;然后依次筛选出满足条件的情况。 代码实现 package TEST;public class Main {public static void main(String[] args) {for (int i 5; i < 10000; i) {int temp i;if (temp % 5 1) {temp temp…

纯前端JS实现人脸识别眨眨眼张张嘴案例

在不久之前我发布了一个案例&#xff0c;是java通过百度云人脸识别接口实现活体检测&#xff08;张张嘴和眨眨眼&#xff09;的案例&#xff0c;大家可以去看看&#xff1a;人脸识别活体检测之眨眨眼和张张嘴&#xff0c;今天我就抽空更新一下纯JS的活体检测吧。 首先给大家看一…

年度大片:StackOverflow 2017开发者调查报告

Stack Overflow 发布了 2017 开发者调查报告&#xff0c;此次有超过 64,000 名开发人员参与调查&#xff0c;分别对其技能、工具、学习趋势等数据进行了统计&#xff0c;现将其中一些有趣的数据和趋势撷取出来分享给大家。 一、开发角色 开发类型 大约有四分之三的受访者是 we…

oracle导库需要删除原始库,导入dmp文件时,需要删除原有ORACLE数据库实例

导入dmp文件时&#xff0c;对于已存在的数据库实例及表处理方式&#xff1a;删除实例。1.以管理员身份登录sqlplus / as sysdba2.停止实例shutdown abort;执行结果&#xff1a;ORACLE instance shut down.3.启动实例独占启动的选项是exclusive&#xff0c;表示只允许一个例程使…

数组中一种数出现奇数次和两种数出现奇数次

题目描述 思路分析 代码实现 package class01;/*** 创建人 wdl* 创建时间 2021/4/10* 描述*/ public class num1ornum2 {public static void main(String[] args) {int arr1[]{1,2,2,2,1,3,3};printOddTimesNum1(arr1);int arr2[]{1,2,2,2,1,3,3,5};printOddTimesNum2(arr2);}…

基于微软开发平台构建和使用私有NuGet托管库

本篇blog包含使用TFS2017&#xff0c;VS2017等平台和工具搭建和使用NuGet库等基本过程&#xff0c;为团体提供更加自动化和高效的研发活动支持。 作为以产品线或者以专属业务为扩展的项目类型的软件研发团体&#xff0c;都会有自己的基础软件框架和功能模块的软件产品智力资产库…

你真的理解CAP理论吗?

最近在学习消息中间件的时候&#xff0c;接触到了分布式系统&#xff0c;进而接触到CAP理论&#xff0c;上一次接触还是在年初的时候公司的技术分享会上&#xff0c;有人在介绍项目的时候简单介绍了这个CAP理论&#xff0c;但并没有深入研究。这次&#xff0c;该是时候研究一下…

264. 丑数 II---LeetCode---JAVA(动态规划)

class Solution { public int nthUglyNumber(int n) {int[] nums new int[n];//初始化数组int index2 0;int index3 0;int index5 0;int tmp 1;nums[0] 1;//初始化第一个值&#xff0c;当n等于1的时候直接是1int cnt 1;while (cnt < n) {tmp Math.min(nums[index2] …

老司机实战Windows Server Docker:4 单节点Windows Docker服务器简单运维(下)

上篇中&#xff0c;我们主要介绍了使用docker-compose对Windows Docker单服务器进行远程管理&#xff0c;编译和部署镜像&#xff0c;并且设置容器的自动启动。但是&#xff0c;还有一些重要的问题没有解决&#xff0c;这些问题不解决&#xff0c;就完全谈不上运维&#xff1a;…

2018蓝桥杯省赛---java---C---4( 第几个幸运数)

题目描述 思路分析 直接暴力 代码实现 package TEST;public class Main {public static void main(String[] args) {long n 59084709587505L, cnt 0;for (long a 1; a < n; a * 3)for (long b 1; b < n; b * 5)for (long c 1; c < n; c * 7)if (a * b * c <…

MySQL year()函数

转载自 MySQL year()函数 MySQL YEAR函数简介 YEAR()函数接受date参数&#xff0c;并返回日期的年份。请参阅YEAR()函数的语法&#xff1a; YEAR(date);YEAR()函数返回一个指定日期的年份值&#xff0c;范围为1000到9999&#xff0c;如果日期为零&#xff0c;YEAR()函数返回…

MySQL协议.NET Core实现(一)

一个有技术追求的研发团对&#xff0c;无论使用什么框架、什么工具、什么语言&#xff0c;团队里应该有人有能力把控所使用框架、工具、语言的每一个核心功能的实现细节。团队里的每个成员应该根据自身所长挑选其中一块做深入研究&#xff0c;并把研究成果分享给团队&#xff0…

2018蓝桥杯省赛---java---C---7(缩位求和)

题目描述 问题描述在电子计算机普及以前&#xff0c;人们经常用一个粗略的方法来验算四则运算是否正确。 比如&#xff1a;248 * 15 3720 把乘数和被乘数分别逐位求和&#xff0c;如果是多位数再逐位求和&#xff0c;直到是1位数&#xff0c;得 2 4 8 14 > 1 4 5; 1 …

龙芯linux内核,龙芯的linux kernel,内核开发与编译

在很久很久以前&#xff0c;linux被视为geek极客的玩具。自行升级Linux内核&#xff0c;对普通用户来说&#xff0c;简直是天方夜谭。曾经的曾经&#xff0c;升级内核需要很多纷繁复杂的步骤&#xff0c;也需要花费很多的时间。但是&#xff0c;现在不一样了。内核的安装可以方…

2018蓝桥杯省赛---java---C---8(等腰三角形)

题目描述 问题描述本题目要求你在控制台输出一个由数字组成的等腰三角形。 具体的步骤是&#xff1a;先用1,2,3&#xff0c;…的自然数拼一个足够长的串 用这个串填充三角形的三条边。从上方顶点开始&#xff0c;逆时针填充。 比如&#xff0c;当三角形高度是8时&#xff1a;1…

Git,Git Flow,GitLab使用指南

高效利用一次蹲坑时间&#xff0c;看看如何使用Git Flow进行高效开发&#xff0c;什么才是Git提交的正确姿势&#xff0c;怎样使用GitLab进行Code Review&#xff1a; 使用Git Flow高效开发&#xff1b;Git提交正确姿势&#xff0c;Commit message编写指南&#xff1b;使用Git…

arm linux gcc 编译,Linux arm-linux-gcc交叉编译环境配置

Linux下的arm-linux-gcc交叉编译环境安装安装arm-linux-gcc(1) 打开终端&#xff0c;使用sudo命令进入从超级管理员&#xff1a;sudo su输入超级管理员密码。(2) 使用cd命令进入桌面&#xff1a;cd Desktop(3)复制arm-linux-gcc-4.4.3.tar.gz安装包到Ubuntu桌面下面(4)打开终端…

2019蓝桥杯省赛---java---C---1(求和)

题目描述 代码实现 package TEST;public class Main {public static void main(String[] args) {int cnt 0;for (int i 1; i < 2019; i)if (check(i)) cnt i;System.out.print(cnt);}static boolean check(int n) {String an"";if (a.contains("2")…