用了Dapper之后通篇还是SqlConnection,真的看不下去了
一:背景
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,真的看不下去了的更多相关文章
- 你真的看懂Android事件分发了吗?
引子 Android事件分发其实是老生常谈了,但是说实话,我觉得很多人都只是懂其大概,模棱两可.本文的目的就是再次从源码层次梳理一下,重点放在ViewGroup的dispatchTouchEvent方 ...
- 深入Dapper.NET源码 (文长)
目录 前言.目录.安装环境 Dynamic Query 原理 Part1 Dynamic Query 原理 Part2 Strongly Typed Mapping 原理 Part1 : ADO.NE ...
- 一次Dapper高并发测试报告记录. 结果....
一直听说dapper的数据处理能力很强. 我也一直很喜欢. 不过最近的一次压力测试却出乎我的意料.... 好久没写东西,感觉自己都不知道怎么表达自己的意思了. 另外 这次的测试也是自己才开始的 . ...
- 开源项目 05 Dapper
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...
- Asp.net 面向接口可扩展框架之数据处理模块及EntityFramework扩展和Dapper扩展(含干货)
接口数据处理模块是什么意思呢?实际上很简单,就是使用面向接口的思想和方式来做数据处理. 还提到EntityFramework和Dapper,EntityFramework和Dapper是.net环境下 ...
- .Net下几种ORM框架的对比
1.Entity Framework(重量级)2.NHibernate(重量级)3.Dapper(轻量级)4.PetaPoco(轻量级)5.MyBatis.Net (介于EF和Dapper之间) 对比 ...
- 【.net深呼吸】(WCF)OperationContextScope 的用途
一个WCF服务可以实现多个服务协定(服务协定实为接口),不过,每个终结点只能与一个服务协定关联,并指定调用的唯一地址.那么,binding是干吗的?binding是负责描述通信的协议,以及消息是否加密 ...
- 移动web端的react.js组件化方案
背景: 随着互联网世界的兴起,web前端开发的方式越来越多,出现了很多种场景开发的前端架构体系,也对前端的要求日益增高,早已经不是靠一个JQuery.js来做前端页面的时代了,而今移动端变化最大,近 ...
- iPhone被盗后怎么?这篇文章只办针对iOS7后的系统
中午准备去吃饭的时候,今天看到Tungbaby的手机被盗后怎么做?http://www.jianshu.com/p/f13f49cd9b90 碰巧我的手机也被盗了.就来分享下我的经验吧.由于我当时是在 ...
随机推荐
- java 面向对象(九):类的结构:构造器(一)简介;属性赋值顺序;JavaBean的概念
1.构造器(或构造方法):Constructor构造器的作用: * 1.创建对象 * 2.初始化对象的信息2.使用说明: * 1.如果没显式的定义类的构造器的话,则系统默认提供一个空参的构造器 * 2 ...
- 网络编程-HTTPS
明文: 对称加密: 非对称:(公钥:pk 私钥:sk) 对称+非对称: 先用非对称方式发送num1给server,server用私钥得出key(由num1算出来),自此,约定C.S以此key(num1 ...
- (五)学习了解OrchardCore笔记——灵魂中间件ModularTenantContainerMiddleware的第一行②模块的功能部分
在(三)的时候已经说到模块集合用ForEachAsync的扩展方法分配多个任务,把每个modules的ManifestInfo分析出来的功能加入ConcurrentDictionary.我们先看看这个 ...
- 1.对Java平台的理解。“Java是解释执行”对吗
Java本身是一种面向对象的语言,最显著的特性有两个方面,一是所谓的“书写一次,到处运行”,能够非常容易地获得跨平台能力: 另外就是垃圾收集(GC),Java通过垃圾收集器(Garbage Colle ...
- 为什么大家都在用Fiddler?
在我们做接口测试的时候,经常需要验证发送的消息是否正确,或者在出现问题的时候,查看手机客户端发送给server端的包内容是否正确,就需要用到抓包工具.常用的抓包工具有fiddler.wireshark ...
- koa中是如何封装获取客户端IP的?
案例 var koa = require('koa') var app = new koa() app.use(function (ctx,next) { ctx.body = ctx.ip }) a ...
- INS-40718 和 INS - 30516
RAC 安装的时候报错, INS-40718 这个是自己填写的 scan name 和 /etc/hosts 里定义的不一致 可以cat /etc/hosts 看一下 INS - 30 ...
- 少儿编程:python趣味编程第一课
本文仅针对8-16岁的青少年,所以流程是按如何去教好中小学生走的,并不适合成人找工作学习,因为进度也是按照青少年走的 大家好,我是C大叔,从事少儿编程行业三年有余(2016年从事少儿编程行业,少儿编程 ...
- 二分图&网络流初步
链接 : 最小割&网络流应用 EK太低级了,不用. 那么请看:#6068. 「2017 山东一轮集训 Day4」棋盘,不用EK你试试? dinic模板及部分变形应用见zzz大佬的博客:网络流学 ...
- u盘安装 osx 出现 “不能验证”
关于安装是出现关于出现“不能验证”错误: 解决办法 :打开终端 在"终端"里面修改时间 输入:date 032208102015.20