l 引言
自從 .net 真正走入開發(fā)人員那天起,“效率”兩個字就一直成為眾多程序員津津樂道的話題。無論是從開發(fā)模式(cross language)、系統(tǒng)框架(.net framework),還是各種使用方便的工具(vs.net),無一不體現(xiàn)出了它的勝人一籌。
同時,在另一方面,.net 是否可以真正勝任企業(yè)級應(yīng)用(enterprise application)開發(fā)的重任,卻依然爭論不斷,褒貶不一。
通常來說,對于一個企業(yè)級應(yīng)用,需要考慮的方面很多,如安全、性能、伸縮性、易用性等。在本文中,作者更愿意與大家一起探討 .net 下數(shù)據(jù)訪問層的相關(guān)技術(shù),這可能是在多層架構(gòu)(n-tier architecture)誕生之日起就受到廣泛關(guān)注的敏感話題,而對于大部分開發(fā)人員來說,這也可能是項目中最讓人沮喪的部分,甚或引起爭議最多的部分。
在以下論述中,為統(tǒng)一起見,作者暫時將數(shù)據(jù)訪問層簡稱為dal(data access layer)。
l 分析問題
簡單統(tǒng)計分析后,就不難發(fā)現(xiàn),dal之所以讓人畏懼,并非出于技術(shù)本身的問題,甚至恰恰相反,很多開發(fā)人員認(rèn)為這是最沒有技術(shù)含量的部分之一(就作者經(jīng)歷的大小項目來看,該層所占的開發(fā)時間一般較短,也是很多開發(fā)人員不愿意承擔(dān)的“苦差”),只是架構(gòu)需要或者某些思想作怪(如:為dal而dal)才加入了這所謂的第四層(傳統(tǒng)三層架構(gòu)并沒有提出dal思想)。
dal的提出,確實對傳統(tǒng)的架構(gòu)模式提出了巨大挑戰(zhàn),加入的目的肯定也是希望借其進(jìn)一步提高生產(chǎn)效率,在這種模式下,理想情況是:大部分開發(fā)人員從此擺脫dba之苦,甚或徹底斷絕與數(shù)據(jù)庫的直接關(guān)系,sql之痛將離我們而去,整個oo世界從此清靜。
不過,理想歸理想,能否成為現(xiàn)實則需通過項目檢驗。
接下來,作者試圖分析比較流行且較有代表性的幾種解決方案,看看能否從中得出一些有價值的結(jié)論,并為我們今后在設(shè)計與實現(xiàn)dal時提供一些借鑒。
u ado.net
首先,提到.net下的dal,立刻映入眼簾的就是ado.net。
沒錯,幾乎所有的dal解決方案(請允許作者使用solution而非
framework)都必須從它發(fā)展而來,沒得選擇,這也是具有.net特色的
實現(xiàn)方式(相比較j2ee)。
排除商業(yè)因素及clr本身的需要,ado.net真正帶給我們的東西
不多,值得一提的也就dataset(就作者經(jīng)歷的項目來說,使用更多的是
datatable和dataview)。從微軟早期的內(nèi)存數(shù)據(jù)庫(memory database)
鮮有人問津到今天的dataset大行其道,這其中的曲折實非片言只語所
能道盡,總之,有一點可以肯定,正是有了dataset這種選擇,.net下
的dal才能象今天這般百花齊放,大家的思路才能更趨開闊。
duwamish
這方面有很多好的sample,最經(jīng)典的莫過于微軟大力推薦的企業(yè)級開發(fā)套餐:duwamish。
對于希望學(xué)習(xí).net下dal設(shè)計的朋友,這是一個不錯的起點,這
方面的完整剖析,大家可以參考“csdn開發(fā)高手,2003.11”,本文不
再贅述。
作者自己參與的一個項目中就使用了duwamish方案,當(dāng)時限于工
期,感覺這是一個很好的參考,沒做深入分析就開始設(shè)計了?,F(xiàn)在回想
起來,發(fā)現(xiàn)還是有很多不足之處。
舉個簡單的例子,duwamish方案中并沒有考慮cache management,
而這對于企業(yè)級應(yīng)用來說,某些時候就是一個不得不考慮的問題;另一
方面,雖然duwamish中告別了sql語句(全部采用存儲過程實現(xiàn)),
但數(shù)據(jù)庫痕跡依舊十分明顯,比如:某些字段名稱的定義,關(guān)聯(lián)表名稱
的定義等等。
還有一個十分頭疼的問題是在開發(fā)過程中體現(xiàn)出來的。一開始,那
些比較簡單的數(shù)據(jù)表還比較容易實現(xiàn),到了一些包含相互關(guān)系的數(shù)據(jù)表
時,我們的dal工程師就感到了壓力,到后來,幾乎又做了一遍dba
在數(shù)據(jù)庫建模時早已做過的工作,只不過,這次將數(shù)據(jù)庫腳本換作了
c# 實現(xiàn)(或者說:將數(shù)據(jù)庫結(jié)構(gòu)換成了表面上具有oo特色的dataset)
而已。
可能,duwamish的實現(xiàn)比較經(jīng)典,但在實際應(yīng)用中,有時并不意
味著best practice。就拿我們的項目來說,雖然成功交付,但無論從模
型復(fù)用角度,還是開發(fā)效率來說,都不能算很成功。套用一句流行語:
其實我們可以做得更好!
petshop
ado.net上另一個值得參考的dal實現(xiàn)就是鼎鼎大名的petshop。
當(dāng)然了,與duwamish相似,名氣大未必真的實用。petshop雖然
彌補了duwamish在某些方面的不足,例如:通過factory支持多種數(shù)
據(jù)庫存儲,引入了cache機制,提供了更為便利的sql helper,但也同
時帶來了另一些問題。其中,最麻煩的就是sql語句的引入,而且還
是針對不同數(shù)據(jù)庫存儲的不同sql語句(主要是sql server與oracle
的參數(shù)表示方式不同)。
另一方面,petshop雖然沒有使用dataset而代之以更為簡潔的普通
實體對象(model),但它還是將datareader的結(jié)果轉(zhuǎn)換到了包含實體對
象的列表集合中供離線使用,從這個意義上說,可謂換湯不換藥。甚至,
在某些場合,例如:需要進(jìn)行數(shù)據(jù)過濾,或者在主從數(shù)據(jù)間導(dǎo)航,反而
更為不便(此時,簡單的collection或者list是無法滿足需求的,dba
與dal開發(fā)人員只能再提供其它的方法來達(dá)到目的)。
從上述兩個例子中,我們可以看出,即使在微軟的開發(fā)團(tuán)隊中,也
沒有能夠在dal這個問題上達(dá)成一致。這方面的更詳細(xì)信息,有興趣
的朋友可以參考如下文章:
http://www.microsoft.com/china/community/column/67.mspx。
實戰(zhàn)
上面剖析的兩個解決方案,讓我們看到了它們各自的優(yōu)勢與不足,而企業(yè)級應(yīng)用的復(fù)雜環(huán)境也不太可能要求一個放之四海而皆準(zhǔn)的框架就能解決所有難題,因此,只能根據(jù)具體情況具體分析。
作者曾經(jīng)參與一個(.net)大型外包項目的開發(fā)工作,有幸一睹其dal的設(shè)計思想,深感震撼,在此與各位朋友一起共同探討。
以sql server所帶northwind數(shù)據(jù)庫為例,如下就是一段基于該dal的調(diào)用代碼(作者做了一些名稱上的調(diào)整):
// 根據(jù)employeeid返回其title
boemp = new employeedal();
boemp.keys[“emp_id”] = 1; // 注意:實際字段名為:employeeid
boemp.select();
string strtitle = boemp[“emp_title”]; // 注意:實際字段名為:title
……
// 根據(jù) city 返回所有符合條件的 employee
boemp = new employeedal();
boemp.keys[“emp_city”] = “seattle”;
boemp.select(); // 注意:該方法與上面的調(diào)用完全相同
datatable dtemp = boemp.table;
如果不考慮對象創(chuàng)建(可以采用object pooling或者cached object)以及調(diào)用后的處理,實際的代碼只有兩行!
更讓人吃驚的是,上述employeedal類沒有任何真正意義上的實現(xiàn)代碼,僅僅是聲明了類名,然后從一個通用基類繼承而已!!
最優(yōu)雅的地方還不在于此,實際上,就算在那個基類中,也根本看不到sqlconnection或者oracleadapter之類的幫派之爭。
相信大家也猜出來了,沒錯,它是借鑒了petshop的實現(xiàn),采用了factory模式來保證dal可以適用于不同的數(shù)據(jù)庫存儲。不過,這種實現(xiàn)與petshop還是有很大的區(qū)別:至少,它沒有產(chǎn)生不同的sql語句,更沒有出現(xiàn)不同的參數(shù)調(diào)用方式(sql server中一般使用“@”符號,oracle中一般使用“:”符號),所有幫派一視同仁!
這其中,當(dāng)然得益于factory的實現(xiàn)技巧,但更重要的因素還在于設(shè)計方式的精妙。其實,在.net framework中,已經(jīng)提供了這種設(shè)計方式的基石,說白了,就是system.data中的那些interface(如:idbconnection,idataadapter等)。
在這樣的設(shè)計基礎(chǔ)上,我們針對每一個dal類,就不再需要為不同的數(shù)據(jù)庫存儲提供不同的數(shù)據(jù)存取實現(xiàn)了。例如:在petshop中,針對訂單數(shù)據(jù)需要實現(xiàn)order類,很自然的,系統(tǒng)為sql server與oracle分別實現(xiàn)了order類并使用不同provider(sqlclient,oracleclient)提供的方法進(jìn)行操作。而在實際調(diào)用時,petshop通過factory模式動態(tài)創(chuàng)建真正的order類并激活相應(yīng)的方法,一個面向不同數(shù)據(jù)庫存儲的方案就躍然紙上。
其實,petshop這種方案已經(jīng)比較靈活了,如果更能省去“撰寫不同order類”之苦,那就真的送佛送到天了j。而所有這些功能,在作者所參與的這個項目中,已經(jīng)完全搞定了!
至于上面的“employeedal(當(dāng)然,包括其它所有dal類)沒有任何真正實現(xiàn)代碼”,只不過玩了一個小小的配置技巧而已:將不同的dal類與相關(guān)的stored procedure(請注意:不是table或view)按照namespace分別存儲到xml文件中。
可能大家已經(jīng)看出來了,理論上,甚至只需要一個dal類就可以完成上述所有的工作!但在實際操作中,不同的dal類可能還是有一些數(shù)據(jù)處理上的細(xì)微差別(比如:數(shù)據(jù)校驗,格式轉(zhuǎn)換等)。
總的來說,在這樣一個大項目中,不可能要求所有開發(fā)人員(除了dba,dal framework developer)都去了解ado.net的方方面面,雖然作者對此頗有研究,但在這個項目中,卻從頭至尾只用到了兩個類:datatable,dataview(甚至連transaction都無需了解)!
新聞熱點
疑難解答
圖片精選