擴充套件 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>
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 無與倫比的體驗。
相關推薦
擴充套件 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
Django(1)python3.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和官網上搜尋資料,很快就找到
開始寫博客,學習Linq(1)
設計 查詢 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
LFS(1)——軟件包及其功能
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 類似,但這個大括號在有些地方是強制要