新聞中心
一、上章回顧

創(chuàng)新互聯(lián)專注于北屯網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供北屯營(yíng)銷型網(wǎng)站建設(shè),北屯網(wǎng)站制作、北屯網(wǎng)頁(yè)設(shè)計(jì)、北屯網(wǎng)站官網(wǎng)定制、微信小程序定制開(kāi)發(fā)服務(wù),打造北屯網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供北屯網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
上篇我們簡(jiǎn)單講述了服務(wù)層架構(gòu)模式中的幾種,并且講解了服務(wù)層的作用及相關(guān)的設(shè)計(jì)規(guī)范,其實(shí)我們應(yīng)該知道,在業(yè)務(wù)邏輯層中使用領(lǐng)域模型中使用服務(wù)層才
能發(fā)揮出***的優(yōu)勢(shì),如果說(shuō)我們?cè)跇I(yè)務(wù)邏輯層還是使用非領(lǐng)域模型的模式話,服務(wù)層的作用僅體現(xiàn)在解耦作用。其實(shí)在業(yè)務(wù)邏輯層采用領(lǐng)域模型時(shí),我們前面說(shuō)的持
久化透明的技術(shù),其實(shí)我們可以通過(guò)服務(wù)層來(lái)做,我們?cè)诜?wù)層中處理領(lǐng)域?qū)ο笮畔⒌某志没僮鳌.?dāng)然本篇可能不會(huì)深入討論持久化透明的具體實(shí)現(xiàn),后面會(huì)單獨(dú)開(kāi)
篇來(lái)講述,我們先來(lái)回顧下上篇講解的內(nèi)容:
上圖大概描述了上篇我們講解的內(nèi)容,如果您想要詳細(xì)的了解服務(wù)
層的相關(guān)內(nèi)容,請(qǐng)參考:系統(tǒng)架構(gòu)師-基礎(chǔ)到企業(yè)應(yīng)用架構(gòu)-服務(wù)層,后續(xù)我們將會(huì)對(duì)一些前端的服務(wù)層還會(huì)進(jìn)行擴(kuò)展的講解,請(qǐng)大家提出報(bào)告意見(jiàn)和建議。
二、摘要
本篇將主要以系統(tǒng)中與數(shù)據(jù)庫(kù)存儲(chǔ)介質(zhì)進(jìn)行交互的數(shù)據(jù)訪問(wèn)層進(jìn)行詳細(xì)的介紹講解,我想這塊也是大家比較熟悉也是經(jīng)常在項(xiàng)目中一定會(huì)用到的部分,我們知道
數(shù)據(jù)訪問(wèn)層通常我們都把這塊的內(nèi)容提升出來(lái),寫成通用的類庫(kù),在我們前面講解的分層架構(gòu)的系統(tǒng)中,基本上可以說(shuō)業(yè)務(wù)對(duì)象中的數(shù)據(jù)都要通過(guò)數(shù)據(jù)訪問(wèn)層將業(yè)
務(wù)數(shù)據(jù)持久化到存儲(chǔ)介質(zhì)中。其實(shí)目前有很多的好的ORM框架已經(jīng)很好的實(shí)現(xiàn)了數(shù)據(jù)訪問(wèn)層,而且得到了很廣泛的應(yīng)用,當(dāng)然我們本篇也會(huì)以這些通用的框架為例舉
例說(shuō)明數(shù)據(jù)訪問(wèn)層中的一些設(shè)計(jì)模式。本章將會(huì)以下列幾個(gè)典型關(guān)注點(diǎn)展開(kāi)去講:
1、數(shù)據(jù)訪問(wèn)層的職責(zé)及與其他組件的交互。
2、如何設(shè)計(jì)自己的數(shù)據(jù)訪問(wèn)層。
3、實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)層必須滿足的4個(gè)基本要求,持久化CRUD、查詢服務(wù)、事務(wù)服務(wù)、實(shí)現(xiàn)并發(fā)等。
4、結(jié)合目前流行的幾類框架分析框架提供的數(shù)據(jù)訪問(wèn)層功能的優(yōu)劣。
下面我們將針對(duì)上面的幾個(gè)關(guān)注點(diǎn)依次展開(kāi)去說(shuō),希望能通過(guò)本文的講解,讓您對(duì)數(shù)據(jù)庫(kù)訪問(wèn)層有個(gè)更深刻的認(rèn)識(shí)和了解。
三、本章大綱
1、上章回顧。
2、摘要。
3、本章大綱。
4、數(shù)據(jù)訪問(wèn)層介紹。
5、如何設(shè)計(jì)數(shù)據(jù)訪問(wèn)層。
6、實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)的四項(xiàng)原則。
7、本章總結(jié)。
8、系列進(jìn)度。
9、下篇預(yù)告。
四、數(shù)據(jù)庫(kù)訪問(wèn)層簡(jiǎn)介
本節(jié)將會(huì)主要針對(duì)數(shù)據(jù)訪問(wèn)層的功能及職責(zé)進(jìn)行講解,分析之前在業(yè)務(wù)邏輯層中的四種模式與數(shù)據(jù)訪問(wèn)層之間的關(guān)系。我們閑來(lái)看看數(shù)據(jù)訪問(wèn)層與業(yè)務(wù)邏輯層中的
四種模式之間的關(guān)系。
我們?cè)诒竟?jié)中的講解主要是以領(lǐng)域模型為例進(jìn)行分析講解,因?yàn)橹挥蓄I(lǐng)域模型模式,我們才能將數(shù)據(jù)訪問(wèn)層抽離出來(lái),分成單獨(dú)的層,這樣能夠做到領(lǐng)域?qū)ο蟪志?/p>
化透明。接下來(lái)我們來(lái)看看數(shù)據(jù)訪問(wèn)層都需要提供什么要的功能及數(shù)據(jù)訪問(wèn)層本身的職責(zé)是什么。
數(shù)據(jù)庫(kù)訪問(wèn)層是唯一知道如何操作存儲(chǔ)介質(zhì)的入口,可以這么來(lái)說(shuō),基于數(shù)據(jù)訪問(wèn)層之上,我們調(diào)用數(shù)據(jù)庫(kù)訪問(wèn)層提供的方法,我們就能完成數(shù)據(jù)的存儲(chǔ)與讀取,
所以我們可以知道,數(shù)據(jù)訪問(wèn)層應(yīng)該是與數(shù)據(jù)庫(kù)直接是獨(dú)立的。還有就是我們的數(shù)據(jù)訪問(wèn)層如何能實(shí)現(xiàn)不同類型的數(shù)據(jù)庫(kù)的動(dòng)態(tài)的切換,而我們不需要修改任何的程序
功能等,可能我們?cè)陂_(kāi)發(fā)的過(guò)程中都會(huì)遇到這樣的問(wèn)題。所以我們希望可以對(duì)數(shù)據(jù)訪問(wèn)層完成動(dòng)態(tài)的配置,通過(guò)不同的配置項(xiàng)完成對(duì)象數(shù)據(jù)庫(kù)訪問(wèn)的切換,這里我想大
家都是比較熟悉的,通過(guò)XML配置文件來(lái)完成數(shù)據(jù)庫(kù)的切換,前面我們說(shuō)了我們的需求,是必須實(shí)現(xiàn)無(wú)縫的數(shù)據(jù)庫(kù)的切換,那么我們?nèi)绾螌?shí)現(xiàn)呢,這里我們可以通過(guò)定
義一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)接口,然后通過(guò)實(shí)現(xiàn)不同的數(shù)據(jù)庫(kù)的細(xì)節(jié),來(lái)實(shí)現(xiàn)這樣的切換。目前很多流行的框架都是采用這樣的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)庫(kù)的動(dòng)態(tài)切換。當(dāng)然有時(shí)候我們
的項(xiàng)目中肯能不讓我們使用開(kāi)源的通用框架,這時(shí)候我們可能就需要自己去實(shí)現(xiàn)這些數(shù)據(jù)訪問(wèn)層的具體細(xì)節(jié)。
當(dāng)然數(shù)據(jù)訪問(wèn)層都必須能夠?qū)?yīng)用程序中的數(shù)據(jù)持久化到存儲(chǔ)介質(zhì)中,通常我們使用的數(shù)據(jù)都是關(guān)系型的數(shù)據(jù)庫(kù),但是我們知道我們?cè)诔绦虻拈_(kāi)發(fā)中,通常采用的
模型都是對(duì)象模型,那么如何實(shí)現(xiàn)對(duì)象模型與關(guān)系模型直接的互相的轉(zhuǎn)換就顯得非常的重要。當(dāng)然這是數(shù)據(jù)訪問(wèn)層的重要功能。通常來(lái)說(shuō),業(yè)務(wù)邏輯層及服務(wù)層不了解
數(shù)據(jù)庫(kù)訪問(wèn)的具體細(xì)節(jié),他們都需要通過(guò)數(shù)據(jù)訪問(wèn)層來(lái)實(shí)現(xiàn)數(shù)據(jù)的交互。一般來(lái)說(shuō)在領(lǐng)域模型中,數(shù)據(jù)訪問(wèn)通常都是在服務(wù)層中進(jìn)行調(diào)用的,而業(yè)務(wù)邏輯層并不關(guān)注數(shù)
據(jù)持久化,所以我們前面說(shuō)的持久化透明的方式也是由此方式來(lái)實(shí)現(xiàn)。
上面我們啰嗦了一大堆,基本上說(shuō)了數(shù)據(jù)訪問(wèn)層的基本需求功能:
下面我們來(lái)看看數(shù)據(jù)訪問(wèn)層的幾個(gè)基本職責(zé)
首先、數(shù)據(jù)訪問(wèn)層應(yīng)該提供基本的持久化操作CRUD的操作,我們知道數(shù)據(jù)訪問(wèn)層是唯一能操作數(shù)據(jù)庫(kù)的一層,因?yàn)槲覀冊(cè)谠O(shè)計(jì)時(shí)需要注意,系統(tǒng)的其他層不能
包含操作數(shù)據(jù)庫(kù)的相關(guān)功能
這里我們通過(guò)類圖可以看到,通過(guò)提供與類對(duì)應(yīng)的數(shù)據(jù)庫(kù)操作類來(lái)提供
相應(yīng)的持久化操作方法,當(dāng)然這不是唯一方式,可行的方式有很多。我們后面會(huì)詳細(xì)討論。
其次、應(yīng)該提供能夠滿足類中信息的讀取操作,一般情況下來(lái)說(shuō)我們經(jīng)常使用的是,根據(jù)主鍵查詢某個(gè)對(duì)象的信息,或者是查詢所有的記錄,或者是根據(jù)條件返
回滿足的集合。
當(dāng)然我們這里定義的查詢類可能是通用的形式,通過(guò)泛型的形式來(lái)做。但是我們知道
領(lǐng)域模型中肯定會(huì)有引用對(duì)象的情況,那么對(duì)于這樣的情況我們?nèi)绾蝸?lái)做呢?我們一般是通過(guò)延遲加載的形式來(lái)處理這樣的要求,我們后面會(huì)依次講解。我們來(lái)看看上
面的通用形式的簡(jiǎn)單代碼格式:
- public class QueryHelper
- {
- ///
- /// 根據(jù)主鍵返回對(duì)象
- ///
- ///
- ///
- ///
- public T GetObjectByKey
(object key) - {
- return default(T);
- }
- ///
- /// 獲取指定類型對(duì)象的總記錄數(shù)
- ///
- ///
- ///
- ///
- public int GetCount
(object key) - {
- return 0;
- }
- ///
- /// 返回指定類型的所有對(duì)象集合
- ///
- ///
- ///
- public List
GetAll () - {
- return new List
(); - }
- }
再次、數(shù)據(jù)庫(kù)訪問(wèn)必須提供事務(wù)的管理,可以說(shuō)不提供事務(wù)操作的數(shù)據(jù)訪問(wèn)層就沒(méi)有辦法使用,因?yàn)檫@樣的數(shù)據(jù)訪問(wèn)層構(gòu)建的系統(tǒng)是不安全的。特別是批量持久
化的過(guò)程中,事務(wù)不但能夠減少與數(shù)據(jù)庫(kù)操作的次數(shù),而且根據(jù)事務(wù)的四個(gè)特性可以提供更好的安全性。我們來(lái)回顧下事務(wù)的四個(gè)特性:
我想我這里就不用一一解釋了,大家都明白的。我們?cè)跀?shù)據(jù)訪問(wèn)層的設(shè)計(jì)中是通過(guò)引入
“工作單元”來(lái)實(shí)現(xiàn)事務(wù)管理的,工作單元后面會(huì)講述到工作單元內(nèi)提供的方法及事務(wù)性。
***、數(shù)據(jù)訪問(wèn)層必須提供處理并發(fā)的功能,我們?cè)谙到y(tǒng)訪問(wèn)的人較多的情況時(shí)肯定會(huì)出現(xiàn)并發(fā)的情況,數(shù)據(jù)訪問(wèn)層如何處理這樣的情況就顯得極其重要了,在
一個(gè)多用戶并發(fā)的系統(tǒng)中,通過(guò)前面提到的事務(wù)來(lái)處理,這時(shí)候可能就會(huì)出現(xiàn)數(shù)據(jù)庫(kù)完整性的問(wèn)題,例如這樣的情況,一個(gè)用戶現(xiàn)在在編輯自己的個(gè)人信息,例如將生
日修改為1985年3月20日,這個(gè)用戶對(duì)應(yīng)的ID是298,這時(shí)候他只是修改了,但是還沒(méi)有提交,此時(shí)管理員也修改了,比如說(shuō)修改了ID為298的這個(gè)用戶信息的地址或
者其他信息,并且提交,此時(shí),用戶將自己編輯的生日提交了,那么數(shù)據(jù)庫(kù)中對(duì)應(yīng)的ID為298的數(shù)據(jù)信息就會(huì)是***修改的數(shù)據(jù)信息,那么之前管理員修改的數(shù)據(jù)信息
就會(huì)發(fā)生丟失,雖然是修改的可能字段不是同一個(gè)字段,這就和我們底層實(shí)現(xiàn)的數(shù)據(jù)訪問(wèn)層有關(guān),當(dāng)然如果說(shuō)我們?cè)跀?shù)據(jù)訪問(wèn)層實(shí)現(xiàn)了,只更新修改過(guò)的數(shù)據(jù)列的值的
話,那么可能不會(huì)存在這樣的情況,當(dāng)然這就和我們底層實(shí)現(xiàn)的數(shù)據(jù)訪問(wèn)層的機(jī)制有關(guān)。
下面我們通過(guò)圖形的方式來(lái)說(shuō)明,更容易理解:
我們來(lái)看看可能的幾種方案,可以對(duì)這樣的并發(fā)做出相應(yīng)的處理?
當(dāng)然這里只是提供了幾個(gè)簡(jiǎn)單可行的辦法,當(dāng)然如果大家還
有更好的辦法,可以告訴我,不勝感激。
當(dāng)然上面的四個(gè)基本職責(zé)是我們?cè)跀?shù)據(jù)訪問(wèn)層必須提供的,還應(yīng)該提供緩存機(jī)制,延遲加載等等包括一些性能方面的優(yōu)化的設(shè)計(jì)等,這些都在后面講解吧。
下面我們來(lái)看看數(shù)據(jù)訪問(wèn)層與其他層直接的關(guān)系與交互,我們前面說(shuō)過(guò),在領(lǐng)域模型下,業(yè)務(wù)邏輯層中的數(shù)據(jù)的持久化都是通過(guò)服務(wù)層來(lái)完成的,下面我們來(lái)看
看各層之間的關(guān)系。我們先來(lái)看看服務(wù)層與數(shù)據(jù)訪問(wèn)層之間的關(guān)系。
服務(wù)層與數(shù)據(jù)訪問(wèn)層之間進(jìn)行交互,服務(wù)層通過(guò)DTO與UI層進(jìn)行交互,服務(wù)層通過(guò)組織業(yè)務(wù)邏輯層中的對(duì)象來(lái)實(shí)
現(xiàn)業(yè)務(wù)流,然后通過(guò)調(diào)用數(shù)據(jù)訪問(wèn)層將業(yè)務(wù)流中的相應(yīng)數(shù)據(jù)進(jìn)行持久化,通過(guò)數(shù)據(jù)訪問(wèn)層來(lái)初始化領(lǐng)域模型。置于直接在表現(xiàn)層中使用數(shù)據(jù)訪問(wèn)層的功能,我們通常是
不推薦這樣做的,一般我們不會(huì)這么做的,我這里就不詳細(xì)的闡述。
五、如何設(shè)計(jì)數(shù)據(jù)訪問(wèn)層
本節(jié)將詳細(xì)的講述如何設(shè)計(jì)出自己的數(shù)據(jù)訪問(wèn)層,滿足上述的幾個(gè)基本要求,那么可以說(shuō)就算完成了基本的數(shù)據(jù)訪問(wèn)層的功能,其實(shí)如果我們從頭開(kāi)始開(kāi)發(fā)一個(gè)
這樣的數(shù)據(jù)訪問(wèn)層將是非常大的工作量,目前流行的很多的ORM框架已經(jīng)提供了豐富的數(shù)據(jù)訪問(wèn)層的功能,能夠非常好的滿足上述的幾項(xiàng)職責(zé)。當(dāng)然本節(jié)還是會(huì)結(jié)合代
碼來(lái)說(shuō)說(shuō)數(shù)據(jù)訪問(wèn)層的具體實(shí)現(xiàn)。
我們前面講述了數(shù)據(jù)訪問(wèn)的3個(gè)基本的功能需求,數(shù)據(jù)庫(kù)獨(dú)立性,可配置性及持久化對(duì)象模式(對(duì)象模型與關(guān)系模型的轉(zhuǎn)換),我們這里先看如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的獨(dú)立
性,我們提出滿足數(shù)據(jù)庫(kù)的無(wú)縫遷移,通過(guò)XML配置文件,配置不同的數(shù)據(jù)庫(kù)鏈接來(lái)實(shí)現(xiàn)這樣的功能,那么首先我們需要定義針對(duì)不同數(shù)據(jù)庫(kù)具體實(shí)現(xiàn),才能完成后續(xù)
的操作,既然我們這里要降低耦合,那么根據(jù)我們前面的面向?qū)ο蟮脑O(shè)計(jì)原則與規(guī)范知道,我們推薦使用面向接口的編程的方式,來(lái)盡量的降低耦合性。我們來(lái)看看具
體的代碼。首先我們定義一個(gè)通用的數(shù)據(jù)訪問(wèn)層的接口。
- ///
- /// 數(shù)據(jù)訪問(wèn)層統(tǒng)一接口
- ///
- public interface IDALInterface
- {
- //CUD 持久化操作
- ///
- /// 創(chuàng)建新的對(duì)象
- ///
- ///
- ///
- int Create(object model);
- ///
- /// 更新對(duì)象
- ///
- ///
- ///
- int Update(object model);
- ///
- /// 刪除對(duì)象
- ///
- ///
- ///
- int Delete(object model);
- //R 查詢服務(wù)
- ///
- /// 查詢所有記錄
- ///
- ///
泛型模型 - ///
- IList
GetAll () where T : class,new(); - ///
- /// 查詢滿足條件的集合
- ///
- ///
- ///
- ///
- IList
GetListByQuery (WhereCondition whereCondition) where T : class,new(); - ///
- /// 返回總行數(shù)
- ///
- ///
- ///
- int GetCount
(); - ///
- /// 返回滿足條件的總行數(shù)
- ///
- ///
- ///
- ///
- int GetCount
(WhereCondition whereCondition); - ///
- /// 根據(jù)主鍵返回對(duì)象模型
- ///
- ///
- ///
- ///
- T GetModelByKey
(object key) where T : class,new(); - //事務(wù)
- ///
- /// 是否事務(wù)執(zhí)行
- ///
- bool IsTransaction
- {
- get;
- }
- ///
- /// 開(kāi)始事務(wù)
- ///
- void BeginTransaction();
- ///
- /// 提交事務(wù)
- ///
- void Commit();
- ///
- /// 回滾事務(wù)
- ///
- void Rollback();
- }
這里定義了基本的幾個(gè)簡(jiǎn)單方法,當(dāng)然其中并沒(méi)有包括并發(fā)的處理,后面會(huì)講到這塊的處理方案的實(shí)現(xiàn), 前面介紹了幾種可行的實(shí)現(xiàn)方式。接口定義好了之后,
數(shù)據(jù)層的具體代碼我這里就不一一的定義貼出來(lái)了,因?yàn)槊糠N不同的數(shù)據(jù)庫(kù)類型就要分別實(shí)現(xiàn),我們這里講解2中不同類型的實(shí)現(xiàn)思路吧,
我們這里講解2中實(shí)現(xiàn)動(dòng)態(tài)創(chuàng)建具體數(shù)據(jù)訪問(wèn)組件的方式,我們先來(lái)講講插件模式。
插件模式
插件模式:插件模式就是通過(guò)外部配置文件中讀取要?jiǎng)?chuàng)建的組件的類型信息,然后調(diào)用組件服務(wù),插件模式的關(guān)鍵點(diǎn)就是服務(wù)不會(huì)與具體實(shí)現(xiàn)聯(lián)系起來(lái),在我們的
分層結(jié)構(gòu)中的解釋就是,服務(wù)層中調(diào)用數(shù)據(jù)訪問(wèn)層中的組件服務(wù),服務(wù)層不關(guān)系具體的調(diào)用方式,服務(wù)層只關(guān)心服務(wù)。而具體的數(shù)據(jù)訪問(wèn)組件是通過(guò)配置文件來(lái)動(dòng)態(tài)的
創(chuàng)建,當(dāng)然這就需要使用.NET中的反射的功能。我們來(lái)看個(gè)圖形畫的描述:
反射工廠通過(guò)讀取配置文件中具體的數(shù)據(jù)配置項(xiàng)及數(shù)據(jù)訪問(wèn)的具
體服務(wù)組件類型,通過(guò)反射工廠來(lái)動(dòng)態(tài)的創(chuàng)建,好了我們來(lái)看看實(shí)例代碼及配置文件。
- value="Data Source=.SQLEXPRESS;Initial Catalog=EasyStore;User ID=sa;Password=123456" />
- value="Data Source=.SQLEXPRESS;Initial Catalog=EasyStore;User ID=sa;Password=123456" />
- value="DAL.SQLServer" /> value="DAL.SQLServer" />
- value="DAL.SQLServer" /> value="DAL.SQLServer" />
上面的配置文件中的ConnectionItem 節(jié)點(diǎn)中配置了數(shù)據(jù)庫(kù)訪問(wèn)的鏈接字符串,DALType 定義了數(shù)據(jù)訪問(wèn)層組件的類型。我們下來(lái)看看反射工廠的示例代碼實(shí)
現(xiàn)。
- public class DALHelper
- {
- private static IDALInterface instance;
- public static IDALInterface GetDAL()
- {
- string assambly = XmlHelper.getVlaue("Assembly");//這里應(yīng)該是自定義的讀取XML節(jié)點(diǎn)的方式
- string type = XmlHelper.getVlaue("DALType");
- Assembly asm = Assembly.Load(assambly);
- instance = (IDALInterface)asm.CreateInstance(type);
- return instance;
- }
- }
我們接下來(lái)看看如何使用這個(gè)數(shù)據(jù)訪問(wèn)層去實(shí)現(xiàn)相應(yīng)的持久化操作:
- public class TestService
- {
- private IDALInterface DAL;
- public TestService()
- {
- DAL = DALHelper.GetDAL();
- }
- public void Create(Test test)
- {
- //相應(yīng)的判定操作
- //創(chuàng)建對(duì)象
- DAL.Create(test);
- }
- }
這樣就實(shí)現(xiàn)了在服務(wù)層對(duì)數(shù)據(jù)訪問(wèn)層的調(diào)用操作,這里是通過(guò)接口調(diào)用的方式來(lái)實(shí)現(xiàn)。我們?cè)賮?lái)看看控制反轉(zhuǎn)的實(shí)現(xiàn)方式吧。
控制反轉(zhuǎn)
控制反轉(zhuǎn)我們?cè)谠O(shè)計(jì)規(guī)范與原則中有過(guò)講解,控制反正通過(guò)動(dòng)態(tài)的將組件注入到引用該組件的對(duì)象中的形式,然后讓引用該組件的對(duì)象使用組件的服務(wù),DI依賴注
入可以看作是控制反轉(zhuǎn)的一個(gè)應(yīng)用實(shí)例,我們可以把控制反轉(zhuǎn)看作是一個(gè)原則。
下面我們來(lái)看看我們?nèi)绾瓮ㄟ^(guò)控制反正的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)層的平滑遷移。當(dāng)然我們知道,肯定是通過(guò)動(dòng)態(tài)注入的方式來(lái)實(shí)現(xiàn),當(dāng)然目前主流的也有很多的IOC動(dòng)
態(tài)注入框架,下面我們將會(huì)借助一些框架來(lái)說(shuō)明如何實(shí)現(xiàn)這樣的功能。
本文將以Enterprise Library5.0為例進(jìn)行講解動(dòng)態(tài)注入的形式。我們先來(lái)看看配置文件的設(shè)置
我們來(lái)看看通過(guò)一個(gè)中間類去實(shí)現(xiàn)相應(yīng)的注冊(cè)代碼:
- ///
- /// 用于動(dòng)態(tài)完成代碼注入的公共類
- ///
- public class IOCContainer
- {
- private static IUnityContainer container;
- private UnityConfigurationSection section;
- public void InitIOC()
- {
- container = new UnityContainer();
- section = (UnityConfigurationSection)System.Configuration.ConfigurationManager.GetSection("unity");
- section.Configure(container);
- }
- public static IDALInterface GetDAL()
- {
- return container.Resolve
(); - }
- }
通過(guò)上述代碼我們實(shí)現(xiàn)了,動(dòng)態(tài)的創(chuàng)建數(shù)據(jù)訪問(wèn)層組件實(shí)例,下面我們來(lái)看看依賴注入的方式去完成相應(yīng)的持久化的功能。我們來(lái)看看服務(wù)層的代碼
- ///
- /// 測(cè)試服務(wù)層
- ///
- public class TestService
- {
- private IDALInterface DAL;
- public TestService(IDALInterface dal)
- {
- DAL = dal;
- }
- public void Save(Test test)
- {
- DAL.Create(test);
- }
- }
這里我們是采用構(gòu)造函數(shù)注入的方式來(lái)實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)層的動(dòng)態(tài)注入的,當(dāng)然除了構(gòu)造函數(shù)注入,還有其他的方式,我們這里只是舉例說(shuō)明,一般來(lái)說(shuō)依賴注入有
如下的幾種形式
具體的我這里就不舉例說(shuō)明了,大家可以網(wǎng)上查查有很多的例
子,我們平時(shí)也常用這些方式。
六、實(shí)現(xiàn)數(shù)據(jù)訪問(wèn)的四項(xiàng)原則
在第四節(jié)中我們講解了數(shù)據(jù)訪問(wèn)層的四個(gè)原則,那么我們?cè)谧约旱臄?shù)據(jù)訪問(wèn)層中如何實(shí)現(xiàn)這幾個(gè)原則呢,我想針對(duì)***個(gè)原則持久化的原則,我們前面只是簡(jiǎn)單
的講解如何實(shí)現(xiàn)數(shù)據(jù)庫(kù)的獨(dú)立性,下面我們先來(lái)看看持久化的操作,也就是我們說(shuō)的CUD的操作,并不包括具體的查詢服務(wù),查詢服務(wù)也是我們數(shù)據(jù)訪問(wèn)層必須提供四
個(gè)原則之一,我們后面都會(huì)講解,我們先來(lái)看看CUD的實(shí)現(xiàn)。我們?cè)谧龀志没?wù)的時(shí)候,一般情況下,我們會(huì)定義一個(gè)統(tǒng)一的數(shù)據(jù)訪問(wèn)層接口,然后提供持久化服
務(wù),事務(wù)等等,通常有一些數(shù)據(jù)訪問(wèn)層共性的部分,我們都通過(guò)一個(gè)抽象類來(lái)實(shí)現(xiàn),抽象類將實(shí)現(xiàn)接口中的部分功能,然后通過(guò)定義一些抽象成員函數(shù),讓具體的數(shù)據(jù)
訪問(wèn)層去實(shí)現(xiàn)相應(yīng)的功能。我們這里以上節(jié)我們定義的IDALInterface為例講解基類的簡(jiǎn)單實(shí)現(xiàn)。
我們將原來(lái)的接口層進(jìn)行相關(guān)的優(yōu)化操作將CUD操作單獨(dú)抽取出來(lái),通過(guò)ICUDMapper接口來(lái)定義
- ///
- /// 數(shù)據(jù)庫(kù)持久化訪問(wèn)器
- ///
- public interface ICUDMapper
- {
- //CUD 持久化操作
- ///
- /// 創(chuàng)建新的對(duì)象
- ///
- ///
- ///
- int Create(object model);
- ///
- /// 更新對(duì)象
- ///
- ///
- ///
- int Update(object model);
- ///
- /// 刪除對(duì)象
- ///
- ///
- ///
- int Delete(object model);
- }
然后我們來(lái)看看基類接口層的簡(jiǎn)單實(shí)現(xiàn),作為所有數(shù)據(jù)訪問(wèn)層的父類
- public abstract class BaseDAL : IDALInterface,IDisposable
- {
- protected abstract ICUDMapper GetMapper();
- //CUD 持久化操作
- ///
- /// 創(chuàng)建新的對(duì)象
- ///
- ///
- ///
- public int Create(object model)
- {
- return GetMapper().Create(model);
- }
- ///
- /// 更新對(duì)象
- ///
- ///
- ///
- public int Update(object model)
- {
- return GetMapper().Update(model);
- }
- ///
- /// 刪除對(duì)象
- ///
- ///
- ///
- public int Delete(object model)
- {
- return GetMapper().Delete(model);
- }
- #region IDisposable 成員
- ///
- /// 是否數(shù)據(jù)庫(kù)訪問(wèn)組件資源
- ///
- public void Dispose()
- {
- }
- #endregion
- }
當(dāng)然這里只貼出實(shí)例代碼。當(dāng)然我采用這樣的方式,就是利用我們之前的一篇:Step by Step-構(gòu)建自己的ORM系列-開(kāi)篇這篇中的反射的思想,大家可以看看
特性+反射的思路,我這里的數(shù)據(jù)持久化訪問(wèn)器也是類似的操作,可能底層的實(shí)現(xiàn)就是這樣的方式。
具體的數(shù)據(jù)持久化訪問(wèn)器如何動(dòng)態(tài)的生成SQL語(yǔ)句,緩存優(yōu)化等各方面的內(nèi)容,我們本篇可能不會(huì)深入的講解,我還是想將這塊放在ORM系類篇深入講解。
當(dāng)然我們其實(shí)可能極端的做飯就是為每個(gè)領(lǐng)域模型中的對(duì)象建立一個(gè)數(shù)據(jù)持久化映射器,完成映射,我這里則是通過(guò)創(chuàng)建數(shù)據(jù)庫(kù)的統(tǒng)一模式,在具體的映射器中,
通過(guò)反射取得數(shù)據(jù)對(duì)象的映射信息。我們來(lái)看看實(shí)現(xiàn)的思路吧,具體代碼我就不貼了
大體的流程就是上面說(shuō)的了,細(xì)節(jié)肯定還有很多要注意的地方。
下面我們來(lái)看看查詢服務(wù)的實(shí)現(xiàn):
我想一般的系統(tǒng)80%的時(shí)間數(shù)據(jù)庫(kù)執(zhí)行的操作是查詢,而20%的時(shí)間在完成寫入和修改的操作,當(dāng)然我這里不是絕對(duì)的說(shuō)法。我們希望有一個(gè)工具幫我們自動(dòng)完
成基本的查詢服務(wù),而不是我們手動(dòng)的去書(shū)寫,因?yàn)槲覀儼l(fā)現(xiàn)對(duì)大部分的數(shù)據(jù)集合而言,有一些共性的操作,例如獲取某個(gè)主鍵值的對(duì)象的信息,或者是獲取數(shù)據(jù)庫(kù)表
中的總行數(shù),或者是返回?cái)?shù)據(jù)庫(kù)表的所有記錄,并且如何將關(guān)系數(shù)據(jù)庫(kù)中的關(guān)系模型轉(zhuǎn)換為對(duì)象模型,這都是查詢服務(wù)中應(yīng)該提供的基本功能。下面我們來(lái)看看簡(jiǎn)單實(shí)
現(xiàn)吧。
我想我們還是參考前面的方式,我們將IDALInterface層中的查詢服務(wù)進(jìn)行抽象分離,將查詢服務(wù)單獨(dú)提出來(lái)放在接口IQuery中。代碼如下:
- public interface IQuery
- {
- ///
- /// 查詢所有記錄
- ///
- ///
泛型模型 - ///
- IList
GetAll () where T : class,new(); - ///
- /// 查詢滿足條件的集合
- ///
- ///
- ///
- ///
- IList
GetListByQuery (WhereCondition whereCondition) where T : class,new(); - ///
- /// 返回總行數(shù)
- ///
- ///
- ///
- int GetCount
(); - ///
- /// 返回滿足條件的總行數(shù)
- ///
- ///
- ///
- ///
- int GetCount
(WhereCondition whereCondition); - ///
- /// 根據(jù)主鍵返回對(duì)象模型
- ///
- ///
- ///
- ///
- T GetModelByKey
(object key) where T : class,new(); - }
我們來(lái)看看在基類中的實(shí)現(xiàn)。查詢服務(wù)的相關(guān)實(shí)現(xiàn)
- ///
- /// 查詢服務(wù)組件
- ///
- ///
- protected abstract IQuery GetQuery();
- #region IQuery 成員
- ///
- /// 查詢所有記錄
- ///
- ///
泛型模型 - ///
- public IList
GetAll () where T : class,new() - {
- return GetQuery().GetAll
(); - }
- ///
- /// 查詢滿足條件的集合
- ///
- ///
- ///
- ///
- public IList
GetListByQuery (WhereCondition whereCondition) where T : class,new() - {
- return GetQuery().GetAll
(); - }
- ///
- /// 返回總行數(shù)
- ///
- ///
- ///
- public int GetCount
() - {
- return GetQuery().GetCount
(); - }
- ///
- /// 返回滿足條件的總行數(shù)
- ///
- ///
- ///
- ///
- public int GetCount
(WhereCondition whereCondition) - {
- return GetQuery().GetCount
(whereCondition); - }
- ///
- /// 根據(jù)主鍵返回對(duì)象模型
- ///
- ///
- ///
- ///
- public T GetModelByKey
(object key) where T : class,new() - {
- return GetQuery().GetModelByKey
(key); - }
- #endregion
當(dāng)然根據(jù)不同的數(shù)據(jù)庫(kù)可能定義的查詢語(yǔ)句的格式不同,但是返回的結(jié)果的形式卻可以定義成通用的形式。這樣我們就可以實(shí)現(xiàn)比較通用的查詢服務(wù),也有很好
的通用型和擴(kuò)展性。當(dāng)然我們這里還可以添加分頁(yè)的支持等,只是添加的條件有限制,實(shí)現(xiàn)方式還是相同。
下面我們來(lái)看看數(shù)據(jù)訪問(wèn)層功能必須職責(zé)之事務(wù)性,我們都知道事務(wù)性的幾大特性,通過(guò)事務(wù)性來(lái)提供數(shù)據(jù)的安全性。我們這里給出一種思路去實(shí)現(xiàn)這樣的事務(wù)
性,我們?cè)跀?shù)據(jù)訪問(wèn)層中定義一組事務(wù)單元,通過(guò)一個(gè)列表維護(hù)這些事務(wù)單元,當(dāng)執(zhí)行提交時(shí),我們將這個(gè)事務(wù)范圍內(nèi)的所有事務(wù)單元進(jìn)行提交,否則不進(jìn)行真正的提
交操作。我們來(lái)看看吧,我們?cè)谥暗腎DALInterface中已經(jīng)定義了事務(wù)相關(guān)的幾個(gè)方法,我們這里同樣抽出來(lái),進(jìn)行分解,抽出來(lái)一個(gè)單獨(dú)的接口ITransation,具體
代碼如下:
- public interface ITransaction
- {
- ///
- /// 是否事務(wù)執(zhí)行
- ///
- bool IsTransaction
- {
- get;
- }
- ///
- /// 開(kāi)始事務(wù)
- ///
- void BeginTransaction();
- ///
- /// 提交事務(wù)
- ///
- void Commit();
- ///
- /// 回滾事務(wù)
- ///
- void Rollback();
- }
基類中的代碼如下:
- #region ITransaction
- ///
- /// 是否事務(wù)執(zhí)行
- ///
- public bool IsTransaction
- {
- get
- {
- return GetTransaction().IsTransaction;
- }
- }
- ///
- /// 開(kāi)始事務(wù)
- ///
- public void BeginTransaction()
- {
- GetTransaction().BeginTransaction();
- }
- ///
- /// 提交事務(wù)
- ///
- public void Commit()
- {
- GetTransaction().Commit();
- }
- ///
- /// 回滾事務(wù)
- ///
- public void Rollback()
- {
- GetTransaction().Rollback();
- }
- ///
- /// 返回事務(wù)單元列表
- ///
- List
list - {
- get;
- }
- ///
- /// 執(zhí)行事務(wù)單元的操作,執(zhí)行數(shù)據(jù)操作并提交
- ///
- ///
- void Excute(TransationUnit unit);
- #endregion
- ///
- /// 事務(wù)組件服務(wù)
- ///
- ///
- protected abstract ITransaction GetTransaction();
事務(wù)組件中添加了特殊的事務(wù)單元,用來(lái)存儲(chǔ)事務(wù)執(zhí)行的操作CUD,還有就是要事務(wù)執(zhí)行的數(shù)據(jù)對(duì)象,當(dāng)然事務(wù)對(duì)象中的CRD操作就是使用前面講解的CRD操作
的方式,我們來(lái)看看吧,我們來(lái)看看事務(wù)單元的形式。
- ///
- /// 事務(wù)單元
- ///
- public class TransationUnit
- {
- ///
- /// CUD枚舉
- ///
- public enum CUDEnum
- {
- Create,
- Update,
- Delete
- }
- private CUDEnum _cudType;
- private object _model;
- public TransationUnit(object model, CUDEnum cudType)
- {
- _model = model;
- _cudType = cudType;
- }
- }
我們?cè)谑聞?wù)處理中,我們只執(zhí)行事務(wù)列表中的操作,置于非事務(wù)列表中的單元我們將不做任何處理,所以我們只要是事務(wù)執(zhí)行的事務(wù)單元,我們必須將指定操作類
型,當(dāng)然我們還可以更靈活,我們通過(guò)在事務(wù)單元中設(shè)置屬性判定是否在事務(wù)中,如果不在事務(wù)中,我
網(wǎng)站欄目:系統(tǒng)架構(gòu)師談企業(yè)應(yīng)用架構(gòu)之?dāng)?shù)據(jù)訪問(wèn)層
文章路徑:http://www.5511xx.com/article/coojsip.html


咨詢
建站咨詢
