网站设计一般多长时间,下载网站系统源码,北京做网站费用,python18+21一#xff1a;背景1. 讲故事前几天看公司一个新项目的底层使用了dapper#xff0c;大家都知道dapper是一个非常强大的半自动化orm#xff0c;帮程序员解决了繁琐的mapping问题#xff0c;用起来非常爽#xff0c;但我还是遇到了一件非常不爽的事情,如下代码所示#xff1… 一背景1. 讲故事前几天看公司一个新项目的底层使用了dapper大家都知道dapper是一个非常强大的半自动化orm帮程序员解决了繁琐的mapping问题用起来非常爽但我还是遇到了一件非常不爽的事情,如下代码所示public class UserDAL : BaseDAL{public ListUserModel GetList(){using (SqlConnection conn new SqlConnection(ConnectionString)){var list conn.QueryUserModel(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 ExecuteT(FuncSqlConnection, T func){using (SqlConnection connection new SqlConnection(ConnectionString)){return func(connection);}}}
有了父类通用的 Execute 方法接下来子类中就可以直接用它啦改造如下public class UserDAL : BaseDAL{public ListUserModel GetList(){return Execute((conn) {var list conn.QueryUserModel(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 ExecuteT(FuncSqlConnection, T func){return Execute(ConnectionString, func);}public T ExecuteT(string connectionString, FuncSqlConnection, T func){using (SqlConnection connection new SqlConnection(connectionString ?? ConnectionString)){return func(connection);}}public class UserDAL : BaseDAL{public ListUserModel GetList(string connectionString){return Execute(connectionString, (conn) {var list conn.QueryUserModel(select * from users).ToList();return list;});}}
这样看起来就舒服多了不过还有一个问题我们的程序是给客户独立部署的越简单越好否则实施人员会砍人的所以很多用户操作和api轨迹行为都记录到了sqlserver中这里就有一个 业务表 和 一个 事务日志表而且要作为原子化提交这里就涉及到了事务操作。2. 支持事务操作因为有同时插入两张表的业务逻辑免不了使用 transaction接下来继续扩展 Execute 方法代码如下public T ExecuteT(FuncSqlConnection, SqlTransaction, T func){return Execute(ConnectionString, func);}public T ExecuteT(string connectionString, FuncSqlConnection, 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 的支持貌似也差不多了,异步版的我就不在此封装啦。四总结文章来源于工作中的点点滴滴这也是我的即兴封装大家要是有更好的封装代码欢迎交流独乐乐不如众乐乐本篇就说到这里啦希望对您有帮助。