一:背景

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 的支持貌似也差不多了,异步版的我就不在此封装啦。

四: 总结

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

最新文章

  1. Microsoft Visual Studio 插件
  2. 通过trie树单词自动补全(二)
  3. 答:SQLServer DBA 三十问之一: char、varchar、nvarchar之间的区别(包括用途和空间占用);xml类型查找某个节点的数据有哪些方法,哪个效率高;使用存储 过程和使用T-SQL查询数据有啥不一样;
  4. dojo/aspect源码解析
  5. Model-View-Controller(MVC) is an architectural pattern that frequently used in web applications. Which of the following statement(s) is(are) correct?
  6. 控制非模态弹出框(showModelessDialog)唯一且随父页面关闭
  7. oracle限制用户连接数
  8. [原]sdut2605 A^X mod P 山东省第四届ACM省赛(打表,快速幂模思想,哈希)
  9. careercup-中等难度 17.8
  10. poj1127 Jack Straws(线段相交+并查集)
  11. 分页标签:pager-taglib使用指南
  12. jQuery validate入门
  13. sql语句中单引号嵌套问题
  14. 【开发技术】如何查看项目中struts的版本
  15. springcloud 学习
  16. MyBatis基础入门《十三》批量新增数据
  17. 安装oracle经验
  18. JAVA项目工具包集合
  19. memcache 和 memcached 区别
  20. UVa 11992 Fast Matrix Operations (线段树,区间修改)

热门文章

  1. DVWA学习记录 PartⅡ
  2. 基于NeteaseCloudMusicApi和electron-vue开发网易云音乐--electron-vue初始化
  3. java 面向对象(二十一):属性的赋值顺序
  4. 服务器创建tensorflow环境,nni自动调参记录
  5. WindowsTerminal折腾记
  6. Web For Pentester靶场(xss部分)
  7. Lodash中数组常用方法
  8. Guava的两种本地缓存策略
  9. java中同步异步阻塞和非阻塞的区别
  10. abp vnext 开发快速入门 3 实现权限控制