|
一、開(kāi)篇
距離上篇《Step by Step-構(gòu)建自己的ORM系列-開(kāi)篇》的時(shí)間間隔的太久了,很對(duì)不住大家啊,主要是因?yàn)橛袔讉€(gè)系列必須提前先寫(xiě)完,才能繼續(xù)這個(gè)系列,當(dāng)然我也在
寫(xiě)這幾個(gè)系列的過(guò)程中,對(duì)ORM這個(gè)系列中的原來(lái)的實(shí)現(xiàn)的想法有了新的認(rèn)識(shí)和改進(jìn),當(dāng)然這些都不是說(shuō)是很先進(jìn)的思想或者認(rèn)識(shí),也可能是大家見(jiàn)過(guò)的思路吧,希望后面我能在
寫(xiě)設(shè)計(jì)模式系列的過(guò)程中,穿插講解ORM系列,當(dāng)然我的這個(gè)構(gòu)建的系列,也只能說(shuō)是很簡(jiǎn)易的,自己平時(shí)開(kāi)發(fā)個(gè)小應(yīng)用工具或者什么的,可能用他,因?yàn)槭亲约洪_(kāi)發(fā)的嘛,畢竟
使用起來(lái)還是比較順手的!符合自己的操作習(xí)慣嘛。
當(dāng)然我寫(xiě)這個(gè)系列的過(guò)程中,也會(huì)有自己認(rèn)識(shí)偏激的地方,或者思路不正確的地方,還請(qǐng)大伙多多指出和批評(píng)。我也是在我目前的項(xiàng)目中學(xué)習(xí)到了很多的寶貴的經(jīng)驗(yàn),其實(shí)
我們應(yīng)該能看到ORM給我們提供的方便和不便之處,我們?nèi)∑渚A,剔除糟粕,不過(guò)這真的很難。我其實(shí)對(duì)一些流行的ORM的底層實(shí)現(xiàn),研究的不多也不深,像Nhibernate,我
只是了解Hibernate,是當(dāng)時(shí)從Java中了解過(guò)來(lái)的,不深入,Castle框架倒是用過(guò)一段時(shí)間,EntityFreamWork,我也沒(méi)有用過(guò),只是象征性的下載最新版本,體驗(yàn)了下AOP的
方式,我感覺(jué)其實(shí)有很多的時(shí)候,我們使用AOP的方式,能夠改進(jìn)我們程序的靈活性。這塊可能還需要大牛們多多指點(diǎn)。
我理想的ORM是實(shí)現(xiàn)持久化的透明,這個(gè)怎么理解呢?就是說(shuō)我在程序的開(kāi)發(fā)中,我不想在業(yè)務(wù)代碼中書(shū)寫(xiě)相應(yīng)的持久化操作,也不關(guān)心業(yè)務(wù)層中的去如何調(diào)用你的
ORM,去完成CRUD的操作。我只關(guān)心我的業(yè)務(wù)邏輯,這個(gè)有點(diǎn)像DDD(領(lǐng)域驅(qū)動(dòng)開(kāi)發(fā))里面的領(lǐng)域?qū)恿耍魂P(guān)心領(lǐng)域內(nèi)部的業(yè)務(wù)邏輯,而不關(guān)心其他的東西,這樣方便我們快速
的抓住關(guān)注的東西,而盡量讓與領(lǐng)域無(wú)關(guān)的東西不要影響業(yè)務(wù)領(lǐng)域邏輯的實(shí)現(xiàn)。
二、摘要
本篇主要開(kāi)始講述《Step by Step-構(gòu)建自己的ORM系列-數(shù)據(jù)訪問(wèn)層》關(guān)于數(shù)據(jù)訪問(wèn)層的部分,其實(shí)前面也對(duì)這塊的內(nèi)容有了一定的介紹了,其實(shí)本篇就是教你如何完成
ORM中的數(shù)據(jù)訪問(wèn)層的操作,這里是提供統(tǒng)一的數(shù)據(jù)訪問(wèn)方法的實(shí)現(xiàn)。當(dāng)然這里的操作還是主要集中在數(shù)據(jù)庫(kù)的操作,包括如何根據(jù)實(shí)體對(duì)象返回實(shí)體的列表,包括生成SQL語(yǔ)
句的幾類(lèi)實(shí)現(xiàn),還包括一些實(shí)現(xiàn)后續(xù)的ORM的配置管理的維護(hù),這里就是提供可視化的XML文件的配置,這個(gè)具體怎么來(lái)做呢?因?yàn)槲覀兤綍r(shí)針對(duì)ORM的使用,都是直接修改
XML文件,我們可以提供一個(gè)可視化的界面,讓那個(gè)用戶配置這些相應(yīng)的設(shè)置。通過(guò)這些配置,我們可以實(shí)現(xiàn)數(shù)據(jù)庫(kù)的平滑的遷移,緩存應(yīng)用的配置,包括其他的一些相關(guān)設(shè)置信
息。總體來(lái)說(shuō)這些操作都可以依托于,我們這里的數(shù)據(jù)訪問(wèn)層來(lái)完成。
我們來(lái)看看ORM中數(shù)據(jù)訪問(wèn)層的重要作用和地位吧:
上圖我們知道,我們所有的相關(guān)功能的基礎(chǔ),都是基于數(shù)據(jù)訪問(wèn)層來(lái)做的,所以我們處理好這個(gè)層的相關(guān)邏輯
后,后續(xù)的問(wèn)題就會(huì)比較容易開(kāi)展。下面我們就會(huì)針對(duì)這些疑問(wèn)開(kāi)始
一個(gè)個(gè)的解決我們的數(shù)據(jù)訪問(wèn)層應(yīng)該提供的相關(guān)功能!大體的功能應(yīng)該有如下功能:
1、持久化的操作方法CUD。可以擴(kuò)展提供創(chuàng)建表+其他的修改表等相關(guān)的自動(dòng)腳本工具。提供持久化透明的方式。
2、提供緩存服務(wù),將對(duì)象的相應(yīng)映射信息緩存起來(lái),這樣后續(xù)執(zhí)行生成語(yǔ)句等操作,效率上會(huì)是很大的提升。
3、我們?cè)谔幚韺?duì)象對(duì)于Update語(yǔ)句,應(yīng)該能處理好只能更變化的信息,如果沒(méi)有發(fā)生變化,那么我們是不是不用執(zhí)行更新操作了呢?減少數(shù)據(jù)庫(kù)的操作次數(shù)。
4、提供基礎(chǔ)的查詢方法,以后所有的基于ORM上的查詢基于這個(gè)查詢進(jìn)行擴(kuò)展。提供持久化透明的查詢方式。
5、并發(fā)和事務(wù)的控制。我們這里可能提供一個(gè)內(nèi)部的版本號(hào)的方式來(lái)做,一旦修改過(guò)這個(gè)對(duì)象或者發(fā)生改變,任何時(shí)候的操作,我們都是針對(duì)這個(gè)版本號(hào)的記錄來(lái)做的,版本號(hào)
通過(guò)內(nèi)部提供的方法來(lái)進(jìn)行。
三、本文大綱
1、開(kāi)篇。
2、摘要。
3、本文大綱。
4、ORM之?dāng)?shù)據(jù)訪問(wèn)層分析。
5、ORM相關(guān)代碼實(shí)現(xiàn)。
6、本章總結(jié)。
7、系列進(jìn)度。
8、下篇預(yù)告。
四、ORM之?dāng)?shù)據(jù)訪問(wèn)層分析
我們先來(lái)針對(duì)上面的幾個(gè)問(wèn)題,我們給出實(shí)現(xiàn)思路,來(lái)分析下給出的思路的可行性和如何實(shí)現(xiàn)的解析。具體的代碼下節(jié)給出核心實(shí)現(xiàn)方案。
4.1、提供通用的持久化的操作
這個(gè)具體的解析在上篇中已經(jīng)給出了相應(yīng)的思路了,我們通過(guò)在底層提供相應(yīng)的方法來(lái)做。一般來(lái)說(shuō),對(duì)應(yīng)數(shù)據(jù)庫(kù)的四種操作,我們?cè)跀?shù)據(jù)訪問(wèn)層,也提供了相應(yīng)的語(yǔ)句的
自動(dòng)構(gòu)造的過(guò)程,具體的構(gòu)造,我們前面給出的實(shí)現(xiàn)方案是通過(guò)特性來(lái)實(shí)現(xiàn),特性中定義具體的數(shù)據(jù)庫(kù)字段,類(lèi)型,長(zhǎng)度等一些列的參數(shù)。我這里就不復(fù)述了,我這里分析下我們
這樣實(shí)現(xiàn)的好處。我們知道繼承的方式是挺好的,我為什么這么說(shuō),通過(guò)提供一個(gè)基類(lèi),基類(lèi)中定義通用的CUD的操作方法,這樣只要是繼承這個(gè)類(lèi)的子類(lèi),都會(huì)有CUD的操作
方法了,但是我們?yōu)榱颂峁┏志没该鞯姆桨福敲礋o(wú)疑,對(duì)于持久化的操作,我們就不希望由業(yè)務(wù)邏輯層中的業(yè)務(wù)邏輯對(duì)象來(lái)完成,那么如何來(lái)做呢?我們通過(guò)數(shù)據(jù)訪問(wèn)層,提
供統(tǒng)一的操作方法,讓服務(wù)層來(lái)完成業(yè)務(wù)對(duì)象的持久化操作。這樣就能實(shí)現(xiàn),持久化透明的方案。
所以我們可以這樣來(lái)做,在數(shù)據(jù)訪問(wèn)層中,我們提供一個(gè)接口,接口中定義持久化操作的幾類(lèi)方案,通過(guò)不同的實(shí)現(xiàn)配置,我們可以在XML配置文件中進(jìn)行指定,我們采用
重量級(jí)的ORM還是輕量級(jí)的ORM,這樣我們也理想的實(shí)現(xiàn)了低耦合的特性。
同時(shí),對(duì)于不同的文件的操作,我們可以支持多文件類(lèi)型的寫(xiě)入,當(dāng)然對(duì)于不同的數(shù)據(jù)庫(kù)存儲(chǔ),如果我們利用關(guān)系型數(shù)據(jù)庫(kù)我們需要ORM,對(duì)于對(duì)象數(shù)據(jù)庫(kù)的操作,或者
XML文件的操作,我們這時(shí)候的ORM就變了。
4.2、提供緩存服務(wù)
我們知道,我們第一篇中主要是通過(guò)自定義特性+反射的形式來(lái)處理:我們并沒(méi)有提供完整的特性操作,其實(shí)還有很多的情況,比如說(shuō),我們還可以提供對(duì)視圖的映射,提
供一個(gè)視圖的特性等。還有其他的特性有很多,后續(xù)會(huì)給出完整的代碼結(jié)構(gòu),我們知道自定義特性+反射,如果每次在將對(duì)象映射成數(shù)據(jù)庫(kù)表的時(shí)候,那么效率上是多么的低下
啊,那么這個(gè)時(shí)候,我們可以考慮使用緩存的方式,將數(shù)據(jù)庫(kù)表中的數(shù)據(jù)庫(kù)列與對(duì)象中的屬性列進(jìn)行映射,我們可以把這些對(duì)應(yīng)關(guān)系放在緩存中,那么如果我們?cè)诤罄m(xù)的處理中遇
到與數(shù)據(jù)庫(kù)相關(guān)操作,需要進(jìn)行對(duì)象映射的時(shí)候,我們都先會(huì)去緩存中查找有沒(méi)有指定鍵值的映射數(shù)據(jù)庫(kù)表列存在,存在取出生成SQL語(yǔ)句,否則通過(guò)反射取出對(duì)應(yīng)的數(shù)據(jù)庫(kù)表
列,放在緩存中。下面給出示意圖。將這個(gè)過(guò)程進(jìn)行描述:
當(dāng)然我這里給出的肯定是反向的根據(jù)對(duì)象生成操作數(shù)據(jù)的SQL語(yǔ)句的方式。這里沒(méi)有考慮,當(dāng)數(shù)
據(jù)庫(kù)表發(fā)生變化的時(shí)候,我應(yīng)該自動(dòng)同步緩存中的映射集合信息,當(dāng)然我們可以通過(guò)一定的策略,來(lái)實(shí)現(xiàn)這樣的雙向同步問(wèn)題。例如如下的方式可能就是可行的方案。
通過(guò)上述的方式,我們通過(guò)同步組件,在每次進(jìn)行數(shù)據(jù)操作之前,我們可以應(yīng)用更好的策略,比如記錄或者遍歷文件的修改狀態(tài),對(duì)比文件的最后修改日期,是不是發(fā)生修改,或者當(dāng)某個(gè)文件發(fā)生修
改之后,我們記錄在某個(gè)配置文件中,這樣我們可以提高同步的效率,因?yàn)橥ㄟ^(guò)這樣的方式,我們不需要每次檢查對(duì)象是不是發(fā)生變化了,這樣我們?nèi)绻l(fā)現(xiàn)對(duì)象沒(méi)有發(fā)生變化,
那么我們就不要讓同步組件去檢測(cè)對(duì)象是否發(fā)生變化,這樣就能提高效率,同時(shí)支持當(dāng)映射對(duì)象發(fā)生變化的時(shí)候,我們不用修改我們的關(guān)系數(shù)據(jù)庫(kù)。大家都知道,面向?qū)ο笤O(shè)計(jì)建
模與關(guān)系數(shù)據(jù)庫(kù)的最大難題就是雙方的變化的同步性的方案是很難定的,我這里只是給出一個(gè)簡(jiǎn)單的思路和方式,可能還有更好的方案,也請(qǐng)大家多多告訴我。
4.3、Update語(yǔ)句的操作
我不知道,你們?cè)诿嬖嚨臅r(shí)候,如果你經(jīng)常開(kāi)發(fā)底層的面向?qū)ο蟮腛RM的時(shí)候,應(yīng)該會(huì)遇到這樣的問(wèn)題,我們?cè)诓樵円粋€(gè)映射對(duì)象的時(shí)候,我們可能只需要取出這個(gè)對(duì)象的
部分列,而不是全部的數(shù)據(jù)列,這個(gè)時(shí)候,我們?nèi)绾沃付兀烤褪翘畛鋵?duì)象的時(shí)候,我們只需要填充指定的列?或者我們需要在在保存編輯的時(shí)候,我們不更新未發(fā)生變化的數(shù)據(jù)
庫(kù),其實(shí)主要是要求,我們?cè)谏蒘QL語(yǔ)句的時(shí)候,我們希望我們的更新語(yǔ)句中不要出現(xiàn),沒(méi)有發(fā)生變化的數(shù)據(jù)列的設(shè)置,這個(gè)如何做到呢?我想我們可以通過(guò)如下的2種方式來(lái)
做。
1、通過(guò)對(duì)象的序列化,來(lái)復(fù)制一個(gè)對(duì)象,并且系統(tǒng)中緩存這個(gè)對(duì)象,在編輯之前,緩存,等到提交后,釋放這個(gè)對(duì)象。這個(gè)由系統(tǒng)默認(rèn)的提供方法。前提是標(biāo)記對(duì)象是編
輯狀態(tài),這樣在修改對(duì)象之前進(jìn)行復(fù)制,不然如果修改完了,再?gòu)?fù)制就沒(méi)有什么意義了
2、通過(guò)字典來(lái)保存更新數(shù)值的數(shù)據(jù)列,通過(guò)數(shù)據(jù)字典來(lái)存放。我們?cè)谧值渲写娣庞成涞臄?shù)據(jù)列,將發(fā)生變化的數(shù)據(jù)列和數(shù)據(jù)列的值進(jìn)行標(biāo)記發(fā)生改變,我們?cè)谏筛抡Z(yǔ)
句的時(shí)候。直接遍歷這個(gè)集合,將列狀態(tài)發(fā)生改變的列生成相應(yīng)的操作語(yǔ)句即可。這些都是可行的方式,我們?cè)谇懊娴募軜?gòu)設(shè)計(jì)中也提到過(guò)的。都是給過(guò)思路的,這里我也不多復(fù)
述了。
3、…。可能還有其他的更好的方式,還請(qǐng)大家多提出好的思路,我備注在這個(gè)位置!
4.4、提供基礎(chǔ)的查詢方法。
這里說(shuō)的提供基礎(chǔ)的查詢方法,指的是基于數(shù)據(jù)庫(kù)操作之上,我們提供幾個(gè)常用的查詢方法,包括自動(dòng)生成版本號(hào)的方法等,我們的版本號(hào)可以通過(guò)日期+流水號(hào)的形式來(lái)
生成,或者是其他的情況。GUID也是可行的辦法。不過(guò)維護(hù)起來(lái)可能不是很方便。所以底層提供相應(yīng)的操作方法更容易來(lái)做。
我們這里考慮提供如下的基礎(chǔ)查詢方法,復(fù)雜的查詢方法,我們可以提供一個(gè)入口來(lái)做。例如我們提供如下幾類(lèi)方法:
1、底層生成版本號(hào)的方法,自增ID流水號(hào),根據(jù)不同的生成規(guī)則自定義設(shè)置ID生成規(guī)則,來(lái)組織生成ID的通用方法。
2、提供實(shí)體與數(shù)據(jù)庫(kù)行集之間的轉(zhuǎn)換,我們需要將數(shù)據(jù)庫(kù)記錄轉(zhuǎn)換為實(shí)體集合。通過(guò)查詢方法返回對(duì)象集合。這里提供返回指定主鍵的對(duì)象集合。
3、返回一個(gè)數(shù)據(jù)表或者視圖中的所有記錄。
4、返回傳入分頁(yè)個(gè)數(shù),和分頁(yè)排序字段,分頁(yè)條件的分頁(yè)集合。
5、返回指定列的查詢方法。(這里沒(méi)有想到好的辦法,怎么樣的形式比較靈活能夠動(dòng)態(tài)的指定返回的列,比如說(shuō)1列,10列,5列等),希望大家提出好的意見(jiàn)和建議!
6、提供統(tǒng)一的入口,編寫(xiě)SQL語(yǔ)句傳入到數(shù)據(jù)訪問(wèn)層中進(jìn)行查詢和檢索,根據(jù)指定的返回類(lèi)型來(lái)返回泛型對(duì)象。
4.5、并發(fā)和事務(wù)控制
我想一個(gè)系統(tǒng)中必須考慮的就是事務(wù)處理了,我們進(jìn)行批量操作的時(shí)候,如果數(shù)據(jù)不同步,那就太痛苦了,也是不能使用的系統(tǒng)的,我們希望我們的ORM能夠自動(dòng)的集成
事務(wù)和并發(fā),當(dāng)然這里說(shuō)的并發(fā)是當(dāng)用戶數(shù)上升到一定量的時(shí)候,就會(huì)產(chǎn)生這樣的問(wèn)題,理論上來(lái)說(shuō)只要有2個(gè)以上的用戶,就必須考慮并發(fā)操作!并發(fā)我們有幾個(gè)控制的思路,
總體來(lái)說(shuō)應(yīng)該說(shuō)說(shuō)我們前面的設(shè)計(jì)的內(nèi)部的一個(gè)自動(dòng)生成的版本號(hào),是最好的選擇。具體怎么個(gè)意思呢?我們來(lái)解釋下:
對(duì)于并發(fā)控制,我們知道,并發(fā)控制的問(wèn)題:寫(xiě)丟失,讀出來(lái)的數(shù)據(jù)是臟數(shù)據(jù),無(wú)疑就是這么2個(gè)比較常見(jiàn)的問(wèn)題,那么我們?nèi)绾蝸?lái)對(duì)寫(xiě)丟失進(jìn)行限制呢?目前通用的方案
都是通過(guò)樂(lè)觀鎖來(lái)處理,二個(gè)人可以同時(shí)對(duì)某個(gè)信息進(jìn)行讀取,但是只能有一個(gè)人在進(jìn)行編輯,但是最后修改的內(nèi)容會(huì)把前面修改的信息覆蓋掉,這是樂(lè)觀鎖的處理方式。
悲觀鎖,則是只要有人在修改,那么可能你不能進(jìn)行修改,也不能讀取,這種方式,當(dāng)然可以保證信息的修改的同步性和一致性,但是用戶的易用性和友好性方面不夠人性
化,相比來(lái)說(shuō),有人修改,就不能被其他人修改,但是可以讀取的方式體驗(yàn)方面要差一些,不過(guò)各有使用的場(chǎng)景,一般來(lái)說(shuō),悲觀鎖是樂(lè)觀鎖的一個(gè)補(bǔ)充。
我們這里既不是樂(lè)觀鎖,也不是悲觀鎖的形式,通過(guò)版本來(lái)對(duì)某個(gè)記錄的版本進(jìn)行記錄,一旦發(fā)生改變,那么記錄的版本就要發(fā)生變化,我們這里對(duì)這個(gè)行集的版本的更新
可以通過(guò)ORM提供的版本的生成規(guī)則來(lái)生成一個(gè)版本號(hào),或者是通過(guò)觸發(fā)器來(lái)實(shí)現(xiàn),當(dāng)然性能也是我們需要考慮的部分。
對(duì)于事務(wù),我想一般的不是分布式操作的應(yīng)用,我們通過(guò)數(shù)據(jù)庫(kù)提供的本身的事務(wù)服務(wù)來(lái)完成,基本上就可以滿足日常的需求,也沒(méi)有什么特別難的地方,我想這里我也就
不詳細(xì)的說(shuō)了,我們來(lái)簡(jiǎn)單的說(shuō)下,分布式事務(wù)的一致性,對(duì)于這種分布式的事務(wù)操作,我們可以采用離線并發(fā)模式來(lái)處理。這個(gè)怎么理解呢?就是通過(guò)工作單元來(lái)實(shí)現(xiàn)。我們把
每一個(gè)操作看著一個(gè)工作單元,如果我們?cè)趫?zhí)行某個(gè)事務(wù)操作的過(guò)程中,如果返回是0或者是其他的不是我們期望的結(jié)果時(shí),我們不會(huì)進(jìn)行任何的提交操作,如果全部執(zhí)行通過(guò),
我們循環(huán)所有的工作單元進(jìn)行提交,否則我們回滾所有的系統(tǒng)事務(wù)。我們把這樣的分布式事務(wù),看作一個(gè)業(yè)務(wù)事務(wù),由一些列的工作單元組成,這些工作單元看作是系統(tǒng)事務(wù)。
五、ORM相關(guān)代碼實(shí)現(xiàn)
5.1、CUD的基本實(shí)現(xiàn)代碼:
1,Create語(yǔ)句的實(shí)現(xiàn):
private Dictionary<string, Column> _autoIncrementColumns = new Dictionary<string, Column>();
private Dictionary<string, Column> _updateColumns = new Dictionary<string, Column>();public string TableName
{
get
{
return string.Empty;
}
}public Dictionary<string, Column> UpdateColumns
{
get
{
return this._updateColumns;
}
set
{
this._updateColumns = value;
}
}public Dictionary<string, Column> AutoIncrementColumns
{
get
{
return this._autoIncrementColumns;
}
set
{
this._autoIncrementColumns = value;
}
}public virtual IDbCommand GetDbCommand()
{
// 如果column的值沒(méi)有被更新過(guò),則返回null
if (this.UpdateColumns.Count == 0)
{
return null;
}ArrayList fieldList = new ArrayList();
ArrayList valueList = new ArrayList();
SqlCommand cmd = new SqlCommand();foreach (Column column in this.UpdateColumns.Values)
{
fieldList.Add("[" + column.Key + "]");
valueList.Add("@" + column.Value);
}string fieldString = string.Join(" , ", (string[])fieldList.ToArray(typeof(string)));
string valueString = string.Join(" , ", (string[])valueList.ToArray(typeof(string)));
string cmdText = string.Format("INSERT INTO [{0}]({1}) VALUES({2})",
this.TableName,
fieldString,
valueString);string sqlGetIndentityID = null;
if (this.AutoIncrementColumns.Count == 1)
{
sqlGetIndentityID = string.Format("SELECT [{0}] = SCOPE_IDENTITY()");
}if (sqlGetIndentityID != null)
{
cmdText = cmdText + " ; " + sqlGetIndentityID;
}cmd.CommandText = cmdText;
return cmd;
}
}下面給出Update語(yǔ)句,是從上面的更新集合中編輯,將列的狀態(tài)發(fā)生改變的列添加生成到語(yǔ)句中-示例代碼如下:
public virtual IDbCommand GetDbCommand()
{
// 如果column的值沒(méi)有被更新過(guò),則返回null
if (this.UpdateColumns.Count == 0)
{
return null;
}ArrayList fieldList = new ArrayList();
ArrayList valueList = new ArrayList();
SqlCommand cmd = new SqlCommand();string updateSQL=string.Empty;
foreach (Column column in this.UpdateColumns.Values)
{
if (column.State)
updateSQL += "[" + column.Key + "]=" + "@" + column.Value;
}string cmdText= string.Format("UPDATE {0} SET {1}={2}", updateSQL);
cmd.CommandText = cmdText;
return cmd;
}至于刪除的代碼比較簡(jiǎn)單,我這里就不給出刪除的代碼了,總體來(lái)說(shuō)形式是相同的。
5.2、緩存服務(wù)代碼
我有2篇關(guān)于緩存的介紹,緩存中最難搞的問(wèn)題就是緩存的過(guò)期的問(wèn)題,對(duì)應(yīng)反射的性能問(wèn)題也是存在過(guò)期的問(wèn)題,比如說(shuō)我們的數(shù)據(jù)庫(kù)表發(fā)生變化,或者對(duì)象中的屬性發(fā)
生變化后,那么我們的緩存中的內(nèi)容也需要進(jìn)行更新,不然我們生成的數(shù)據(jù)庫(kù)操作語(yǔ)句將會(huì)不正確。我們這里的策略就是將映射出來(lái)的對(duì)象,放在服務(wù)器中的緩存中,當(dāng)然對(duì)于
B/S和C/S系統(tǒng)中可能采取的緩存方式和策略還是有區(qū)別的。B/S我們的緩存可以采用緩存到服務(wù)器中,或者是通過(guò)緩存服務(wù)器來(lái)完成,一般是通過(guò)Remoting來(lái)將服務(wù)器與緩存
服務(wù)器完成通信。我們看看簡(jiǎn)單的示例代碼吧:
public class Cache
{
private static System.Web.Caching.Cache cache = HttpRuntime.Cache;//這里是默認(rèn)取當(dāng)前應(yīng)用程序的服務(wù)緩存。public static object Get(string key)
{
return cache[key];
}public static bool Remove(string key)
{
return !(null == cache.Remove(key));
}public static void Set(string key, object value)
{
cache.Insert(key, value, null, System.Web.Caching.Cache.NoAbsoluteExpiration, TimeSpan.FromMinutes(3));
}
}
上面給出的緩存類(lèi)的示例代碼,具體的操作,使用反射后,將反射后對(duì)象元數(shù)據(jù)信息緩存起來(lái),通過(guò)對(duì)象名來(lái)緩存:
具體代碼如下:
PropertyInfo[] property = null;
if (Cache.Get("") != null)
{
property = (PropertyInfo[])Cache.Get("");
}
else
{
Type t = Type.GetType("");property = t.GetProperties();
}通過(guò)上面的幾行簡(jiǎn)單的代碼就能表達(dá)出我們上面講述的思路,具體如何過(guò)期,這個(gè)上面也給出了一些思路,可能大伙有更好的思路,我這里就不班門(mén)弄斧了。
5.3,提供基礎(chǔ)的查詢服務(wù)
我想大伙對(duì)于查詢語(yǔ)句的操作,應(yīng)該說(shuō)是司空見(jiàn)慣了吧,我們?nèi)绾文芨玫耐瓿山y(tǒng)一的查詢服務(wù)可能是我們關(guān)心的問(wèn)題,我這里不會(huì)給出多數(shù)據(jù)庫(kù)的實(shí)現(xiàn),但是可以給大伙
一個(gè)思路,我們這里定義返回的查詢命令的時(shí)候,如果說(shuō)支持多數(shù)據(jù)的話,可以定義一個(gè)統(tǒng)一的接口,不同的數(shù)據(jù)庫(kù)提供不同的實(shí)現(xiàn)接口,然后根據(jù)統(tǒng)一的ORM配置來(lái)調(diào)用不同的
組件來(lái)生成SQL語(yǔ)句,完成調(diào)用操作。
相關(guān)的查詢服務(wù)代碼如下:
/// <summary>
/// 系統(tǒng)自動(dòng)生成的版本號(hào)
/// </summary>
/// <returns></returns>
public string GetVersion()
{
return DateTime.Now.Year.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + DateTime.Now.Minute.ToString() + DateTime.Now.Second.ToString();
}public int GetMax<T>()
{
//根據(jù)T的類(lèi)型獲取T的最大列,完成查詢操作。
string sqlText = " Select MAX(ISNULL(列名,0))+1 FROM TableName";return 0;
}public List<T> GetAll<T>()
{
//根據(jù)T的類(lèi)型獲取T的最大列,完成查詢操作。
string sqlText = " Select * FROM TableName";return new List<T>();
}public List<T> GetList<T>(string condition,int pagesize,string orderField)
{
//根據(jù)T的類(lèi)型獲取T的最大列,完成查詢操作。
string sqlText = " Select * FROM TableName where " + condition + " order by " + orderField;return new List<T>();
}
上面給出的不是全部的代碼,部分代碼還是大家自己去完成吧,我這里想的是,一些客戶比較復(fù)雜的自定義代碼通過(guò)一個(gè)接口傳入的形式,來(lái)完成基礎(chǔ)查詢服務(wù)的調(diào)用。
我們這里給出通用的接口定義:
CommandType CommandType
{
get;
set;
}string whereCondition
{
get;
set;
}string orderCondition
{
get;
set;
}string TableName
{
get;
set;
}Column[] ColumnList
{
get;
set;
}string SQL
{
get;
set;
}
給出默認(rèn)幾類(lèi)示例的實(shí)現(xiàn):
public class BaseSQL : ISelect
{
public System.Data.CommandType CommandType
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}public string whereCondition
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}public string orderCondition
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}public string TableName
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}public Column[] ColumnList
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}public string SQL
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}具體調(diào)用的代碼如下:
public class SpecialSQL : BaseSQL
{
public void Test()
{
this.TableName = "";
this.SQL = " SELECT * FROM TEST ";
this.whereCondition = " ID=4 ";
this.orderCondition = " ORDER BY ID DESC ";
}
}當(dāng)然這里的繼承的方式不是很推薦,可以采用抽象工廠的模式,來(lái)創(chuàng)建這個(gè)查詢對(duì)象,然后我們?cè)谡{(diào)用這個(gè)查詢對(duì)象的地方,我們可以自定義這個(gè)SQL查詢對(duì)象,后臺(tái)的
ORM自動(dòng)解析,完成自定義SQL語(yǔ)句的統(tǒng)一查詢服務(wù)入口。
當(dāng)然如果您有更好的方案,可以提出來(lái),非常感謝!
六、本章總結(jié)
本文主要是講述ORM中的數(shù)據(jù)訪問(wèn)層,我這里由于一些特殊的原因,代碼給出的不是特別的詳細(xì),一方面是由于之前的那部分的代碼丟了,現(xiàn)在一時(shí)難以還原,所以造成有
些代碼給出的不是特別完整的情況,請(qǐng)大家見(jiàn)諒,文章中的有些部分的內(nèi)容,我在實(shí)現(xiàn)的過(guò)程中也是遇到了不少的問(wèn)題,我現(xiàn)在的具體問(wèn)題列出來(lái),也請(qǐng)大家?guī)臀医鉀Q一下,我的
疑問(wèn),我目前在架構(gòu)設(shè)計(jì)的過(guò)程中遇到如下的問(wèn)題:
1、我在實(shí)現(xiàn)服務(wù)層持久化透明服務(wù)的時(shí)候,我也想把查詢服務(wù)透明,意思就是業(yè)務(wù)對(duì)象與服務(wù)層只通過(guò)DTO來(lái)完成,業(yè)務(wù)對(duì)象的所有數(shù)據(jù)都通過(guò)服務(wù)層的訪問(wèn)來(lái)完成。
2、如果現(xiàn)在有比較復(fù)雜的業(yè)務(wù)邏輯的操作語(yǔ)句的時(shí)候,我的這個(gè)SQL語(yǔ)句放在數(shù)據(jù)訪問(wèn)層好呢?還是放在哪里?應(yīng)該具體的職責(zé)劃分要明確。
3、我只是希望業(yè)務(wù)邏輯層處理業(yè)務(wù)數(shù)據(jù),具體的業(yè)務(wù)數(shù)據(jù)怎么來(lái)的,我想讓業(yè)務(wù)邏輯只關(guān)心DTO。
4、對(duì)于這樣的服務(wù)層提供的統(tǒng)一查詢方式的話,我在表現(xiàn)層調(diào)用的時(shí)候,如何傳參,能夠很好的組織參數(shù)的傳遞和調(diào)用,傳統(tǒng)的方式不再目前的考慮當(dāng)中。
it知識(shí)庫(kù):Step by Step-構(gòu)建自己的ORM系列-數(shù)據(jù)訪問(wèn)層,轉(zhuǎn)載需保留來(lái)源!
鄭重聲明:本文版權(quán)歸原作者所有,轉(zhuǎn)載文章僅為傳播更多信息之目的,如作者信息標(biāo)記有誤,請(qǐng)第一時(shí)間聯(lián)系我們修改或刪除,多謝。