本文原始路徑: https://www.zybuluo.com/Ivony/note/14074html
DbUtility v3 是一個開源的輕量級數據庫訪問框架,源代碼經過 Apache 協議發佈,能夠用於商業用途。最新的版本能夠經過 NuGet 進行下載,項目及源代碼下載地址:git
https://github.com/Ivony/DbUtility程序員
DbUtility 第一個版本公開於七年前,關於 DbUtility 的歷史和 DbUtility 的使用,請參考下面這篇博客:github
http://www.cnblogs.com/Ivony/p/3659746.html
https://www.zybuluo.com/Ivony/note/8277數據庫
做爲一個開源項目,DbUtility 不只僅致力於幫助你們簡化數據庫訪問,也很是歡迎和期待你們的共同參與,不管是提交 Bug 或者單元測試,或是新的特性需求,以及本身動手爲 DbUtility 增長更多有趣的功能,都是參與開源項目的方式。這篇文章面向全部有志於爲 DbUtility 增添自定義功能的程序員,介紹 DbUtility 的擴展架構。架構
DbUtility v3 相較於以前版本的最大區別,也是 DbUtility v3 傲視其餘輕量級數據庫訪問框架的地方,就是其優良的擴展架構。正如以前的介紹所述,DbUtility 將一個數據庫查詢分爲三個部分:框架
這三個部分各有一個關鍵的接口,分別爲:異步
譬如說 SqlDbUtility 類型即是面向 SQL Server 數據庫的查詢執行器實現類型,其聲明爲:ide
public class SqlDbUtility : IAsyncDbExecutor<ParameterizedQuery>, IAsyncDbExecutor<StoredProcedureQuery>, IDbTransactionProvider<SqlDbUtility>
IAsyncDbExecutor
是 IDbExecutor
的異步版本,表示能夠異步執行指定類型的查詢。能夠看出來SqlDbUtility實現了兩個查詢執行器接口,分別是 IAsyncDbExecutor<ParameterizedQuery>
和 IAsyncDbExecutor<StoredProcedureQuery>
這表示這個類型的對象既能夠執行 ParameterizedQuery
類型(參數化查詢)的查詢,也能執行 StoredProcedureQuery
類型(存儲過程)的查詢。函數
接下來咱們嘗試擴展一個查詢構建方法,就像T( "SELECT * FROM Users" )
同樣。
假定咱們常常會遇到一個場景,須要獲取某個表的全部數據,若是直接使用T來構建參數化查詢,則所需寫的SQL語句不少: SELECT * FROM TableName
,咱們但願簡化爲 DT( "TableName" )
的形式,該如何作呢?
首先咱們要肯定咱們是否須要構建一種新的查詢類型,由於構建新的查詢類型,須要同時修改查詢執行器,在本例中暫不涉及這麼深刻的問題。咱們假定暫且借用參數化查詢對象,只是簡化其生成代碼。
那麼首先咱們須要瞭解的一個事實是,全部的查詢構建方法其實都是擴展方法,針對特定的查詢執行器,對其進行擴展。若是咱們生成的是一個參數化查詢,那麼咱們須要一個參數化查詢執行器才能執行,因此咱們要針對參數化查詢執行器進行擴展。首先新建一個擴展方法所需的靜態類型:
public static class MyExtensions { }
值得注意的是定義擴展方法的類型必須是靜態類型。
而後咱們添加一個擴展方法,由於咱們最終生成的查詢類型是參數化查詢,因此咱們須要對能夠執行參數化查詢的對象進行擴展,像這樣:
public static void DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { throw new NotImplementedException(); }
請注意我這邊的返回值類型尚未填寫,由於這裏涉及到另外一個問題,單純的查詢對象是不能被執行的,爲了達到 db.DT( "Users" ).ExecuteDataTable()
這樣的效果,咱們須要把查詢對象和查詢執行器捆綁起來,這個捆綁後的對象的類型爲 IDbExecutableQuery
(意爲可執行的查詢),因此咱們須要把返回值設置爲 IDbExecutableQuery
類型:
public static IDbExecutableQuery DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { throw new NotImplementedException(); }
DbUtility 已經爲咱們提供了現成的 IDbExecutableQuery
的實現,即 DbExecutableQuery<T>
類型,咱們只須要構建一個查詢對象,再連同查詢執行器一塊兒調用這個類型的構造函數便可:
public static IDbExecutableQuery DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { ParameterizedQuery query = null; return new DbExecutableQuery<ParameterizedQuery>( executor, query ); }
最後,咱們須要構建一個參數化查詢對象,參數化查詢對象做爲基礎查詢對象,有不少種方式來構建,最多見的就是利用模板來構建,若是直接調用 db.T
方法,事實上構建出來的是 DbExecutableQuery<ParameterizedQuery>
類型的對象,好在系統提供了一個靜態類型 Db
來對這些常見任務提供支持:
public static IDbExecutableQuery DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { ParameterizedQuery query = Db.T( "SELECT * FROM " + tableName ); return new DbExecutableQuery<ParameterizedQuery>( executor, query ); }
至此,咱們的第一個擴展就已經完成了,立刻來試一下:
var db = SqlDbUtility.Create( "Database" ); var data = db.DT( "Users" ).ExecuteDataTable();
事實上你知道嗎,db.T
這個方法,其內部實現就是這樣的
如下摘自DbUtility v3源代碼:
public static DbExecutableQuery<ParameterizedQuery> Template( this IDbExecutor<ParameterizedQuery> executor, string template, params object[] parameters ) { return new DbExecutableQuery<ParameterizedQuery>( executor, TemplateParser.ParseTemplate( template, parameters ) ); } public static DbExecutableQuery<ParameterizedQuery> T( this IDbExecutor<ParameterizedQuery> executor, string template, params object[] parameters ) { return Template( executor, template, parameters ); }
接下來,咱們把這個方法再進一步擴展,咱們但願用戶調用這個方法的時候,再也不返回一個可執行的查詢對象,而是直接執行查詢,並將 DataTable 返回就行了,相信聰明的你應該很快就能想到怎樣寫了:
public static class MyExtensions { public static DataTable DT( this IDbExecutor<ParameterizedQuery> executor, string tableName ) { ParameterizedQuery query = Db.T( "SELECT * FROM " + tableName ); return new DbExecutableQuery<ParameterizedQuery>( executor, query ).ExecuteDataTable(); } }
沒錯,藉助優秀的可擴展架構,DbUtility能夠被任意改造爲任何你所喜歡 API 的形式,這種逆天的擴展性,是深深的植入在 DbUtility 總體架構模型設計中的。構成了 DbUtility 無與倫比的體驗。