擴展 DbUtility (1)

本文原始路徑: 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 將一個數據庫查詢分爲三個部分:框架

  • 查詢執行器
  • 查詢構建器
  • 結果構建器

這三個部分各有一個關鍵的接口,分別爲:異步

  • IDbExecutor where T : IDbQuery 定義某種類型查詢的查詢執行器。
  • IDbQuery 定義特定的數據庫查詢
  • IDbExecuteContext 定義數據庫查詢執行上下文,其中包括 DataReader 對象。

譬如說 SqlDbUtility 類型即是面向 SQL Server 數據庫的查詢執行器實現類型,其聲明爲:ide

public class SqlDbUtility :
  IAsyncDbExecutor<ParameterizedQuery>,
  IAsyncDbExecutor<StoredProcedureQuery>,
  IDbTransactionProvider<SqlDbUtility>

IAsyncDbExecutorIDbExecutor 的異步版本,表示能夠異步執行指定類型的查詢。能夠看出來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 無與倫比的體驗。

相關文章
相關標籤/搜索