用了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)),雖然這樣寫邏輯上沒有任何問題,但我有潔癖哈,接下來試着封裝一下,嘿嘿,用更少的代碼作更多的事情。sql

2、模板化代碼封裝探索

一、將模板化的代碼提取到父類中

仔細看上面的模板代碼你會發現,真正的業務邏輯是寫在 using 中的,而該塊中只須要拿到一個 conn 就能夠了,其餘的統一提取封裝到父類中,這就能夠用到 委託函數啦,對不對,用這個思路代碼修改以下:api

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 方法,接下來子類中就能夠直接用它啦,改造以下:app

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 不能框死。異步

二、增長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中,這裏就有一個 業務表 和 一個 事務日誌表,並且要做爲原子化提交,這裏就涉及到了事務操做。sqlserver

3、支持事務操做

由於有同時插入兩張表的業務邏輯,免不了使用 transaction,接下來繼續擴展 Execute 方法,代碼以下:post

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 塞入到各自的業務代碼中便可,子類能夠改造以下:spa

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 的支持貌似也差很少了,異步版的我就不在此封裝啦。設計

4、總結

文章來源於工做中的點點滴滴,這也是個人即興封裝,你們要是有更好的封裝代碼,歡迎交流,獨樂樂不如衆樂樂,本篇就說到這裏啦,但願對您有幫助。


來源:DotNet

相關文章
相關標籤/搜索