用了Dapper之后就不要再见到SqlConnection咯
一、背景
前几天看公司一个新项目的底层使用了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中,这里就有一个 业务表 和 一个 事务日志表,而且要作为原子化提交,这里就涉及到了事务操作。
三、支持事务操作
因为有同时插入两张表的业务逻辑,免不了使用 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 的支持貌似也差不多了,异步版的我就不在此封装啦。
四、总结
文章来源于工作中的点点滴滴,这也是我的即兴封装,大家要是有更好的封装代码,欢迎交流,独乐乐不如众乐乐,本篇就说到这里啦,希望对您有帮助。
来源:DotNet
用了Dapper之后就不要再见到SqlConnection咯的更多相关文章
- 初学C#和MVC的一些心得,弯路,总结,还有教训(3)--Dapper
经过一番深思熟虑,决定先用Dapper吧..... 以下是我感觉比较有用的一些东西 Dapper项目地址 https://github.com/StackExchange/dapper-dot-ne ...
- Dapper
前一段做一个技术分享关于dapper的,现在再总结一下,也好长时间没有更新博客了--,用到的东西 Dapper.AutoFac .AutoMapper.FluentValidation: 下面说一下D ...
- 【原创】打造基于Dapper的数据访问层
[原创]打造基于Dapper的数据访问层 前言 闲来无事,花几天功夫将之前项目里用到的一个数据访问层整理了出来.实现单个实体的增删改查,可执行存储过程,可输出返回参数,查询结果集可根据实际情况返回 ...
- 浏览器默认样式(user agent stylesheet)+cssreset
每种浏览器都有一套默认的样式表,即user agent stylesheet,在写网页时,没有指定的样式,按浏览器内置的样式表来渲染.这是合理的,像word中也有一些预留样式,可以让我们的排版更美观整 ...
- 越狱Season 1-Episode 2: Allen
Season 1, Episode 2: Allen [Previously, on Prison Break] previously: 以前(预先) 前情回顾 -Judge: I find it i ...
- 机器时代的中国字幕(Automata.2014.720p.WEB-DL.DD5.1.H264-RARBG.srt)
看字幕.再也看不下去.自己翻译的位 评价的探讨 1 00:01:58,452 --> 00:02:02,088 人工增雨 期限为32分钟16第二 2 00:02:02,089 --> 00 ...
- 各种ORM框架对比(理论篇,欢迎来观摩)
各种ORM框架对比 目前框架有以下 PetaPoco Dapper.NET Massive Simple.Data Chain PetaPoco 轻量级,以前单文件,目前有维护形成项目级别,适合多个数 ...
- 2.Java 加解密技术系列之 MD5
Java 加解密技术系列之 MD5 序 背景 正文 结束语 序 上一篇文章中,介绍了最基础的编码方式 — — BASE64,也简单的提了一下编码的原理.这篇文章继续加解密的系列,当然也是介绍比较基础的 ...
- UE4 距离场简单分析
距离上一篇博客已经有点久了,中间忙的飞起,忽然发现很久没写了,这样不好,写一篇和工作无关的吧. 一直想搞清UE4距离场的原理,网上有几乎找不到任何有关UE4距离场实现的内容,加上上篇末说要写一个完全的 ...
随机推荐
- 【漏洞复现】Shiro<=1.2.4反序列化漏洞
0x01 概述 Shiro简介 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.使用Shiro的易于理解的API,您可以快速.轻松地获得任何应用程序,从 ...
- Docker(5)- docker version 命令详解
如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 作用 显示 Docker 版本信 ...
- [Codeforces 580D]Fizzy Search(FFT)
[Codeforces 580D]Fizzy Search(FFT) 题面 给定母串和模式串,字符集大小为4,给定k,模式串在某个位置匹配当且仅当任意位置模式串的这个字符所对应的母串的位置的左右k个字 ...
- python数据分析03Python的数据结构、函数和文件
我们会从Python最基础的数据结构开始:元组.列表.字典和集合.然后会讨论创建你自己的.可重复使用的Python函数.最后,会学习Python的文件对象,以及如何与本地硬盘交互. 3.1 数据结构和 ...
- 庐山真面目之三微服务架构Consul版本实现
庐山真面目之三微服务架构Consul版本实现 一.简介 在上一篇文章<庐山真面目之二微服务架构NGINX版本实现>中,我们已经探讨了如何搭建基于Nginx 网关的微服务 ...
- 释放至强平台 AI 加速潜能 汇医慧影打造全周期 AI 医学影像解决方案
基于英特尔架构实现软硬协同加速,显著提升新冠肺炎.乳腺癌等疾病的检测和筛查效率,并帮助医疗科研平台预防"维度灾难"问题 <PAGE 1 LEFT COLUMN: CUSTOM ...
- 消息队列--ActiveMQ单机部署
一.环境需求 1,Centos7环境 2,jdk 1.8+ 3,主机名的命名方式中不能含有'_'字符 二.软件包下载 1,下载路径 wget http://mirror.bit.edu.cn/apac ...
- GAMES101系列笔记一 图形学概述与线性代数入门
概述+线性代数 为什么学习图形学? Computer Graphics is AWESOME! 主要涉及内容: 光栅化 曲线和网格 光线追踪 动画与模拟 Differences between CG ...
- Spider_实践_beautifulsoup静态网页爬取所有网页链接
# 获取百度网站首页上的所有a标签里的 href属性值: # import requests # from bs4 import BeautifulSoup # # html = requests.g ...
- [读书笔记] Python语言及其应用
记录下秋招期间看的一本Python工具书<Python语言与其应用>,查漏补缺,部分内容整理如下: 易混淆概念 1.1 删除 - del,remove()和pop() 1.2 复制 - 浅 ...