天天看點

關于O/R Mapping的思考,我們應該選擇什麼?

最近對orm方面的東西感興趣,有一些想法,想和大家讨論一下。

我覺得hibernate應算算是一個經典且功能強大的orm架構。

它最大的有點是,你可以完全用面向對象分析與設計(ooad)的思想來設計好所有的類,然後該架構就可以以非常人性化的方式為你擷取對象或者持久化對象。

但同時我也發現它的一個缺點,就是當對象與對象之間的關系比較複雜的時候,orm配置檔案會很複雜,且比較難維護。并且當我們要對多個表進行關聯查詢時,雖然架構提供給了我們很多友善的接口讓我們可以通過設定對象的屬性的方式來告訴架構我們需要什麼資料,然後架構會自動為我們生成一個複雜的sql語句,最終傳回給我們資料,但我發現當表關聯較多并且資料量比較大的時候,往往性能不佳。

仔細想了之後,我覺得hibernate的設計者的初衷是好的,就是想讓我們盡可能的不用去關心資料庫,讓我們可以完全以面向對象的方式去實作我們的業務邏輯。但就我個人觀點,我覺得它為我們做了太多的事情,比如一些原本屬于業務邏輯的工作也由它幫我們自動完成了。比如訂單(order)和訂單明細(orderitem),一個order包含了多個orderitem,當我們要删除一個order時,hibernate能幫我們自動删除該訂單下的所有orderitem(當然你也可以選擇不級聯删除)。再比如,當我現在要顯示一個文章的詳細頁面,該頁面需要顯示文章(thread)内容以及所有的回複(posts),如果用hibernate,我們隻需要查詢一個thread即可,而它下面的所有的posts會自動被級聯查詢出來(因為我們已經在配置檔案中配置好了,選擇了非lazyload的情況時)。當然,你或許會覺得這樣不是很好嗎?全部自動化,你就很省心了,不是嗎?确實,當業務邏輯比較簡單時,這樣沒什麼問題,但如果當業務邏輯比較複雜時,我們還能通過簡單的不用動腦子的方式來配置映射關系,并且用簡單的方式把資料查詢出來嗎?比如下面這個例子:

我現在要查詢出一個論壇中某個版塊下具有某種角色的所有使用者,如果我們把這個角色了解為“版主”,那麼就是相當于要查詢出論壇中某個版塊的所有的版主。

我可能會建如下一個表:

<dl></dl>

<dt>sql code</dt>

<dd></dd>

createtable[tb_sectionroleusers]( [sectionid][int]notnull, [roleid][int]notnull, [userid][int]notnull )

sectionid表示版塊id,roleid表示角色id,userid表示使用者id。對于這個表而言,必須是以兩個字段組合去查第三個字段才有意義。比如查某個版塊下具有某個角色的所有的使用者,或者查某個版塊下某個使用者具有哪些角色。而如果僅僅根據一個字段作為查詢條件進行查詢是沒有意義的,如查詢某個版塊下的所有的角色及使用者,沒有意義。

假設我們的使用者表是下面這樣的:

createtable[tb_users]( [entityid][int]identity(10000,1) notnull, [nickname][varchar](64) null, [avatarfilename][varchar](128) null,[avatarcontent][image]null )

那麼對于“查某個版塊下具有某個角色的所有的使用者”這個需求而言,我們需要的是關聯上面這兩個表,并且以sectionid和roleid作為查詢條件,查詢出tb_users表中的相關記錄。

對于上面這個相對複雜的需求,我們該怎麼利用hibernate來配置映射關系并且該怎麼樣來設計對象呢?我相信hibernate肯定可以,但估計要比我之前舉的例子要複雜難懂的多吧。因為這裡大概涉及到三個原子對象(section、role、user),并且這三個原子對象可能會兩兩進行組合,并且都是m:n的關系,并且必須要同時根據兩個條件進行查詢才有意義。

經過我的思考,我覺得之是以我們會覺得麻煩是因為我們把相當一部分業務邏輯都交給hibernate來完成了,hibernate幫我們做了非常多我們覺得很簡單,而要告訴hibernate該怎樣做卻是很麻煩的事情。其實tb_sectionroleusers表是一個關系表,在hibernate中是不會有關系對象這個概念的,對象與對象之間的關系hibernate可以幫我們自動維護,我們無需關心。而我們現在的需求就是想簡單的将一個關系表和一個使用者表關聯,然後查詢出符合條件的資料而已。

我覺得無論是表之間的各種關系還是對象之間的各種關系,都屬于業務邏輯範疇,這些關系的實作不應該交給orm架構自動完成,而應該由我們來自己完成比較好。

另外一個我發現的規律就是,資料庫是關系型資料庫,也就是說資料庫裡所有的表中存放的資料是沒有直接關系的,可以說是扁平狀(平行狀)的,雖然有一些外鍵的限制,但我們不能認為兩個表有外鍵限制就認為他們是一個包含的關系,最多是一個引用的關系。是以,表與表之間都是平行的關系,而非樹狀關系。但純面向對象的思想則不一樣,對象有包含或聚合的關系,可以說是一種具有多個跟節點的樹狀關系。這是兩種完全不一樣的存儲資料方式。hibernate的做法是,資料庫這邊沒有做任何的妥協,對象這邊也沒做任何妥協,是以導緻架構為了轉換這兩個存儲格式完全不一樣的資料必須要做非常複雜的映射;既然這樣,我們為什麼不同時稍微改變一下這兩種資料格式呢,讓資料庫提供一些有關系的“東西”出來,比如建幾個視圖;而對于對象,不需要完全按照面向對象的思想來設計對象,而是也設計一些扁平狀的對象出來,也就是說各個原子對象之間不明确知道它們之間的具體關系,當我們需要連接配接兩個具有某種關系的對象時,我們可以像資料庫的視圖那樣,設計一些組合對象出來,并且所有的這些原子對象以及組合對象也和資料庫一樣,是扁平結構。這些組合對象用于和資料庫的視圖建立映射關系。這樣一來,對象和資料庫兩方都做了一些讓步,但換來的結果是資料存儲格式的統一,這樣的好處就是orm架構在也不用這麼複雜難懂了。我覺得這樣不是滿好的嗎?并且我覺得這樣的設計到更有點像rom了,因為我們的思路已經轉到了以資料庫為基準,然後稍微修改一下對象的設計,進而達到一個資料存儲格式的一緻。然後rom架構基于這個前提,為我們提供一些實用的接口,為我們實作crud操作。相信這樣的rom架構的映射檔案也是簡單并且很好了解的。

好了,就這些吧,大家覺得我的想法如何呢?歡迎大家批評指正。

最後,基于我自己的這個想法,我經過長期的不斷努力和改進,寫了一個小型的rom架構,思路完全和我上面說的一緻。

大家可以看到對于任何資料請求,通過我的架構來處理,rom配置檔案以及對象設計或者業務邏輯是如何的簡單。

下載下傳位址:

<a href="http://www.cnblogs.com/netfocus/archive/2010/01/10/1643207.html" target="_blank">http://www.cnblogs.com/netfocus/archive/2010/01/10/1643207.html</a>