1. 程式人生 > >擴充套件 DbUtility (1)

擴充套件 DbUtility (1)

前言

DbUtility v3 是一個開源的輕量級資料庫訪問框架,原始碼通過 Apache 協議釋出,可以用於商業用途。最新的版本可以通過 NuGet 進行下載,專案及原始碼下載地址:

DbUtility 第一個版本公開於七年前,關於 DbUtility 的歷史和 DbUtility 的使用,請參考下面這篇部落格:

作為一個開源專案,DbUtility 不僅僅致力於幫助大家簡化資料庫訪問,也非常歡迎和期待大家的共同參與,不論是提交 Bug 或者單元測試,或是新的特性需求,以及自己動手為 DbUtility 增加更多有趣的功能,都是參與開源專案的方式。這篇文章面向所有有志於為 DbUtility 增添自定義功能的程式設計師,介紹 DbUtility 的擴充套件架構。

基本結構

DbUtility v3 相較於之前版本的最大區別,也是 DbUtility v3 傲視其他輕量級資料庫訪問框架的地方,就是其優良的擴充套件架構。正如之前的介紹所述,DbUtility 將一個數據庫查詢分為三個部分:

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

這三個部分各有一個關鍵的介面,分別為:

  • IDbExecutor where T : IDbQuery 定義某種型別查詢的查詢執行器。
  • IDbQuery 定義特定的資料庫查詢
  • IDbExecuteContext 定義資料庫查詢執行上下文,其中包括 DataReader 物件。

譬如說 SqlDbUtility 型別便是面向 SQL Server 資料庫的查詢執行器實現型別,其宣告為:

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 無與倫比的體驗。

相關推薦

擴充套件 DbUtility 1

前言 DbUtility v3 是一個開源的輕量級資料庫訪問框架,原始碼通過 Apache 協議釋出,可以用於商業用途。最新的版本可以通過 NuGet 進行下載,專案及原始碼下載地址: DbUtility 第一個版本公開於七年前,關於 DbUtility 的歷史和 DbUtility 的使用,請參

實用jquery擴充套件收集1:在游標處插入內容 和 獲取textarea選中的值

1 $.fn.selection = function(){ 2 var s,e,range,stored_range; 3 if(this[0].selectionStart == undefined){ 4 var selection=do

DSL 系列1 - 擴充套件點的論述與實現

前言 DSL 全稱為 domain-specific language(領域特定語言),本系列應當會很長,其中包含些許不成熟的想法,歡迎私信指正。 1. DSL 簡述 我理解的 DSL 的主要職能是對領域的描述,他存在於領域服務之上,如下圖所示: 其實,我們也可以認為 DomainService

Django1python3.5安裝django擴充套件模組

Django(v1.11.8)的三種安裝方法         1.線上安裝,pip3           sudo pip3 install Django==1.11.8        (1.11.

Echarts地圖使用擴充套件1

本文主要介紹map與geo兩種圖形的聯合使用,以及一些屬性的妙用。 實現效果:在世界地圖上標註省會城市的地理位置,以下只是選擇性的顯示了幾個點,如下圖所示: 實現此效果,需要有兩個series物件,series[0]為顏色漸變的世界地圖,series[1

【ES6】函式的擴充套件1

1.函式引數的預設值 在ES6之前,不能直接為函式的引數指定預設值,只能採用變通的方法。 function log(x, y) { y = y || 'World'; console.log(x, y); } log('Hello') // Hello Worl

MediaWiki LDAP 認證擴充套件1使用者認證

最近在弄wiki,採用的開原始碼是mediawiki,由於需要公司內部所有員工能夠用公司的使用者及密碼登陸,而公司的使用者及密碼全部儲存在LDAP中。所以我首先想到的事搭建mediawiki的環境,於是去官網下載原始碼搭建環境,而後便在google和官網上搜尋資料,很快就找到

開始寫博客,學習Linq1

設計 查詢 lin 數據源 任務 集成 部分 程序 編程   摘自《linq實戰》原文:   軟件很簡單。它可以歸結為兩件事情:代碼和數據。   開發軟件卻並非那麽簡單,其中很重要的一項任務就是編寫處理數據的代碼。   無論選擇了哪種語言,在程序開發得某個時候你將不得不開始

GuozhongCrawler系列教程 1 三大PageDownloader

特點 string null 瀏覽器兼容 ror down odi 系列 lan GuozhongCrawler QQ群 202568714 教程源代碼下載地址:http://pan.baidu.com/s/1pJBmerL GuozhongCrawl

正則表達式1

表達式 正則表達式是計算機科學中的一個重要概念。正則表達式使用單個字符串來描述、匹配一系列符合某個句法規則的字符串。在很多文本編輯器中,正則表達式通常被用來檢索、替換符合某個模式的文本。許多程序設計語言都支持利用正則表達式進行字符串操作。(grep、sed、awk) 為什麽要學習正則表達式?

Angular 4 - The Basics 筆記1: Install

install rst logs nod first log 筆記 npm app Install Node.js Install Angular CLI sudo npm install -g @angular/cli Set-up new app

【Prince2科普】Prince2的七大原則1

步驟 哪些 來看 產品 論證 img .com 驗證 mil 經過前幾講中關於PRINCE2六大要素,四大步驟及整體思維架構的學習,相信各位看官已經對於PRINCE2有了大概的了解,那我們今天的學習內容會正式進入到七大原則內容的分享。 我們先來看一下,PRINCE

SQl 關鍵詞1

order by 結果 tro class 問題 重復 ima 排除 數據 1、Distinct 在表中,可能會包含重復值。這並不成問題,不過,有時您也許希望僅僅列出不同(distinct)的值。 關鍵詞 DISTINCT 用於返回唯一不同的值,過濾掉重復選項。 //

JAVA學習筆記1——a++與++a的區別

col int 演示 opera 解析 代碼 數據 ++i div 需求:此博客用於解釋i++與++i的區別。 過程: 1、名稱解釋 ++:自增,即在原有數據基礎上+1,再賦給原有數據。 2、程序演示 (1)代碼: 1 class OperateDemo 2 { 3

LFS1——軟件包及其功能

shell 選擇 本地化 自制 理解 源代碼 問控制 用戶空間 好的 為了讓自己更加深入理解Linux整個系統架構及工作原理,最近通過LFS學習研究自制Linux系統。參考LFS簡體中文7.7版本。 軟件包及其功能: Acl 管理訪問控制列表(ACL)的工具,用於定義文件和

bash基礎特性1

defaults history 緩沖區 記錄 歷史 所有的環境變量可以通過 ehco $# 查看 #為環境變量 bash的基礎特性:(1)命令歷史 history 環境變量: HISTSIZE:命令歷史記錄的條數 HISTFILE;~/.bash_history HIST

ajax初步1

request get lin tel sogo 調用 oca head sta 搭建服務器環境,創建一個文件夾,本篇搭建為wamp環境,在www目錄下,創建ajax文件夾。 ajax概念: AJAX 指異步JavaScript及XML(Asynchronous JavaS

圖論講解1——圖基礎

同學 根據 tdi sin images 鄰接表 c++ algo ack 前面一直在嗶嗶數論,是不是感覺很煩的慌了?? ╮(╯▽╰)╭唉,你不煩得慌我都煩得慌了! 既然這樣,那我們就改個話題,今天我們就講講圖論。 有的同學就要問圖又是個什麽鬼? 難道是這個嗎?

十二Hibernate中的多表操作1:單向多對一

art 保存 int gen round t對象 情況 映射文件 拋出異常 由“多”方可知“一”方的信息,比如多個員工使用同一棟公寓,員工可以知道公寓的信息,而公寓無法知道員工的信息。 案例一: pojo類 public class Department {

perl 入門知識1

.com 方法 如果 shift vim lis zed http script <一> 語句及註釋: Perl 語句以分號(;)結尾,用 # 作為一行的註釋,沒有其它語言中那種跨行的註釋。代碼塊用大括號圍起來,這個和 C 類似,但這個大括號在有些地方是強制要