一:背景

1. 讲故事

前几天看公司一个新项目的底层使用了dapper,大家都知道dapper是一个非常强大的半自动化orm,帮程序员解决了繁琐的mapping问题,用起来非常爽,但我还是遇到了一件非常不爽的事情,如下代码所示:


public class UserDAL : BaseDAL
{
public List<UserModel> GetList()
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
var list = conn.Query<UserModel>("select * from users").ToList(); return list;
}
} public bool Insert()
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
var execnum = conn.Execute("insert into xxx "); return execnum > 0; }
} public bool Update()
{
using (SqlConnection conn = new SqlConnection(ConnectionString))
{
var execnum = conn.Execute("update xxx ...."); return execnum > 0;
}
}
} public class UserModel {}

扫一下代码是不是总感觉哪里不对劲,是的,为了能使用上Dapper的扩展方法,这里面每个方法中都配上了模板化的 using (SqlConnection conn = new SqlConnection(ConnectionString)),虽然这样写逻辑上没有任何问题,但我有洁癖哈,接下来试着封装一下,嘿嘿,用更少的代码做更多的事情。

二:模板化代码封装探索

1. 将模板化的代码提取到父类中

仔细看上面的模板代码你会发现,真正的业务逻辑是写在 using 中的,而该块中只需要拿到一个 conn 就可以了,其他的统一提取封装到父类中,这就可以用到 委托函数啦,对不对,用这个思路代码修改如下:


public class BaseDAL
{
protected string ConnectionString { get; set; } public T Execute<T>(Func<SqlConnection, T> func)
{
using (SqlConnection connection = new SqlConnection(ConnectionString))
{
return func(connection);
}
}
}

有了父类通用的 Execute 方法,接下来子类中就可以直接用它啦,改造如下:


public class UserDAL : BaseDAL
{
public List<UserModel> GetList()
{
return Execute((conn) =>
{
var list = conn.Query<UserModel>("select * from users").ToList();
return list;
});
} public bool Insert()
{
return Execute((conn) =>
{
var execnum = conn.Execute("insert into xxx ");
return execnum > 0;
});
} public bool Update()
{
return Execute((conn) =>
{
var execnum = conn.Execute("update xxx ....");
return execnum > 0;
});
}
}

改造之后代码是不是清晰多了,仅仅这一个通用方法貌似还不行,起码 ConnectionString 不能框死。

2. 增加ConnectionString 入口参数

相信有不少朋友的公司是做 ToB 的业务,一般是一个商家一个DB的设计思路,这里就需要在 Execute 上增加一个 ConnectionString 字符串参数,你可以通过重载方法 或者 可选参数,改造如下:

        public T Execute<T>(Func<SqlConnection, T> func)
{
return Execute(ConnectionString, func);
} public T Execute<T>(string connectionString, Func<SqlConnection, T> func)
{
using (SqlConnection connection = new SqlConnection(connectionString ?? ConnectionString))
{
return func(connection);
}
} public class UserDAL : BaseDAL
{
public List<UserModel> GetList(string connectionString)
{
return Execute(connectionString, (conn) =>
{
var list = conn.Query<UserModel>("select * from users").ToList();
return list;
});
}
}

这样看起来就舒服多了,不过还有一个问题,我们的程序是给客户独立部署的,越简单越好,否则实施人员会砍人的,所以很多用户操作和api轨迹行为都记录到了sqlserver中,这里就有一个 业务表 和 一个 事务日志表,而且要作为原子化提交,这里就涉及到了事务操作。

2. 支持事务操作

因为有同时插入两张表的业务逻辑,免不了使用 transaction,接下来继续扩展 Execute 方法,代码如下:


public T Execute<T>(Func<SqlConnection, SqlTransaction, T> func)
{
return Execute(ConnectionString, func);
} public T Execute<T>(string connectionString, Func<SqlConnection, SqlTransaction, T> func)
{
using (SqlConnection connection = new SqlConnection(connectionString ?? ConnectionString))
{
connection.Open();
using (var transaction = connection.BeginTransaction())
{
return func(connection, transaction);
}
}
}

上面的代码应该很好理解,将 transaction 作为回调函数的参数,业务逻辑部分直接将 transaction 塞入到各自的业务代码中即可,子类可以改造如下:


public bool Insert()
{
return Execute((conn, trans) =>
{
var execnum = conn.Execute("insert into xxx ", transaction: trans);
if (execnum == 0) return false; var execnum2 = conn.Execute("update xxx set xxx", transaction: trans);
if (execnum2 > 0) trans.Commit(); return execnum > 0;
});
}

这样 Execute 对 transaction 的支持貌似也差不多了,异步版的我就不在此封装啦。

四: 总结

文章来源于工作中的点点滴滴,这也是我的即兴封装,大家要是有更好的封装代码,欢迎交流,独乐乐不如众乐乐,本篇就说到这里啦,希望对您有帮助。

用了Dapper之后通篇还是SqlConnection,真的看不下去了的更多相关文章

  1. 你真的看懂Android事件分发了吗?

    引子 Android事件分发其实是老生常谈了,但是说实话,我觉得很多人都只是懂其大概,模棱两可.本文的目的就是再次从源码层次梳理一下,重点放在ViewGroup的dispatchTouchEvent方 ...

  2. 深入Dapper.NET源码 (文长)

    目录 前言.目录.安装环境 Dynamic Query 原理 Part1 Dynamic Query 原理 Part2 Strongly Typed Mapping 原理 Part1 : ADO.NE ...

  3. 一次Dapper高并发测试报告记录. 结果....

    一直听说dapper的数据处理能力很强. 我也一直很喜欢. 不过最近的一次压力测试却出乎我的意料.... 好久没写东西,感觉自己都不知道怎么表达自己的意思了.   另外 这次的测试也是自己才开始的 . ...

  4. 开源项目 05 Dapper

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  5. Asp.net 面向接口可扩展框架之数据处理模块及EntityFramework扩展和Dapper扩展(含干货)

    接口数据处理模块是什么意思呢?实际上很简单,就是使用面向接口的思想和方式来做数据处理. 还提到EntityFramework和Dapper,EntityFramework和Dapper是.net环境下 ...

  6. .Net下几种ORM框架的对比

    1.Entity Framework(重量级)2.NHibernate(重量级)3.Dapper(轻量级)4.PetaPoco(轻量级)5.MyBatis.Net (介于EF和Dapper之间) 对比 ...

  7. 【.net深呼吸】(WCF)OperationContextScope 的用途

    一个WCF服务可以实现多个服务协定(服务协定实为接口),不过,每个终结点只能与一个服务协定关联,并指定调用的唯一地址.那么,binding是干吗的?binding是负责描述通信的协议,以及消息是否加密 ...

  8. 移动web端的react.js组件化方案

     背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...

  9. iPhone被盗后怎么?这篇文章只办针对iOS7后的系统

    中午准备去吃饭的时候,今天看到Tungbaby的手机被盗后怎么做?http://www.jianshu.com/p/f13f49cd9b90 碰巧我的手机也被盗了.就来分享下我的经验吧.由于我当时是在 ...

随机推荐

  1. java 面向对象(九):类的结构:构造器(一)简介;属性赋值顺序;JavaBean的概念

    1.构造器(或构造方法):Constructor构造器的作用: * 1.创建对象 * 2.初始化对象的信息2.使用说明: * 1.如果没显式的定义类的构造器的话,则系统默认提供一个空参的构造器 * 2 ...

  2. 网络编程-HTTPS

    明文: 对称加密: 非对称:(公钥:pk 私钥:sk) 对称+非对称: 先用非对称方式发送num1给server,server用私钥得出key(由num1算出来),自此,约定C.S以此key(num1 ...

  3. (五)学习了解OrchardCore笔记——灵魂中间件ModularTenantContainerMiddleware的第一行②模块的功能部分

    在(三)的时候已经说到模块集合用ForEachAsync的扩展方法分配多个任务,把每个modules的ManifestInfo分析出来的功能加入ConcurrentDictionary.我们先看看这个 ...

  4. 1.对Java平台的理解。“Java是解释执行”对吗

    Java本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的“书写一次,到处运行”,能够非常容易地获得跨平台能力: 另外就是垃圾收集(GC),Java通过垃圾收集器(Garbage Colle ...

  5. 为什么大家都在用Fiddler?

    在我们做接口测试的时候,经常需要验证发送的消息是否正确,或者在出现问题的时候,查看手机客户端发送给server端的包内容是否正确,就需要用到抓包工具.常用的抓包工具有fiddler.wireshark ...

  6. koa中是如何封装获取客户端IP的?

    案例 var koa = require('koa') var app = new koa() app.use(function (ctx,next) { ctx.body = ctx.ip }) a ...

  7. INS-40718 和 INS - 30516

    RAC  安装的时候报错, INS-40718 这个是自己填写的  scan name 和 /etc/hosts  里定义的不一致  可以cat   /etc/hosts   看一下 INS - 30 ...

  8. 少儿编程:python趣味编程第一课

    本文仅针对8-16岁的青少年,所以流程是按如何去教好中小学生走的,并不适合成人找工作学习,因为进度也是按照青少年走的 大家好,我是C大叔,从事少儿编程行业三年有余(2016年从事少儿编程行业,少儿编程 ...

  9. 二分图&网络流初步

    链接 : 最小割&网络流应用 EK太低级了,不用. 那么请看:#6068. 「2017 山东一轮集训 Day4」棋盘,不用EK你试试? dinic模板及部分变形应用见zzz大佬的博客:网络流学 ...

  10. u盘安装 osx 出现 “不能验证”

    关于安装是出现关于出现“不能验证”错误: 解决办法 :打开终端 在"终端"里面修改时间 输入:date 032208102015.20