前几天看公司一个新项目的底层使用了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 不能框死。