(江蘇大學 計算機科學與通信工程學院, 江蘇 鎮江 212013)
摘 要:基于面向對象的模型與基于關系數學理論之間的阻抗不匹配使得處理數據時無法完整體現對象的特性。對象關系映射提供了溝通對象與關系數據庫的橋梁。分析比較了實體類映射到數據表時的策略,重點研究了NHibernate對象關系映射框架的應用與優勢。
關鍵詞:面向對象; 關系數據庫; 對象關系映射; NHibernate
中圖法分類號:TP311文獻標識碼:A
文章編號:1001 3695(2006)08 0058 03
Research and Application of Object/Relational Mapping in .NET Framework
SUN Dong hai, SONG Shun lin
(School of Computer Science Telecommunications, Jiangsu University, Zhenjiang Jiangsu 212013, China)
Abstract:The impedance mismatch between paradigms based on object oriented theory and relational theory make it impossible to reflect the characteristic of object. Object/Relational Mapping provides a bridge between them. The strategies of mapping entity classes to tables are analyzed and compared. The application and advantage of NHibernate framework are especially introduced.
Key words:Object Oriented(OO); Relational Database; Object/Relational Mapping; NHibernate
如今大多數編程語言是基于面向對象的模型,該模型很好地抽象了真實世界問題域,對現實數據實現了易于理解的自然描述。對于實際應用中需要處理的數據,現在的方法多數是采用關系型數據庫。但是面向對象的模型遵循的一些軟件工程原理如封裝、關聯、聚合、繼承、多態等與關系數據庫遵循的關系數學理論產生的不匹配[1]使得我們在持久化對象過程中遇到了許多困難。在面向對象的開發中,數據訪問層最基本的數據庫操作包括插入對象,刪除對象,更新對象和查詢對象。幾乎所有的項目開發均需要實現這些原子操作,而這些操作在項目開發中都很類似。顯然在每個項目中這種重復而具備相同模式的代碼是一種明顯的浪費。這就催生了Object/Relational Mapping (O/R Mapping)技術的產生。
1 O/R Mapping框架概述
使用面向對象的語言訪問關系數據庫是最簡單,也是最糟糕的辦法,就是在業務類中直接編寫SQL語句。這樣寫的好處在于代碼的編寫效率高,對于非常小型的程序或原型,采用這種方法也未嘗不可。但是缺點是業務類與關系數據庫結構直接耦合,這意味著即使是很小的改變(諸如重命名列或是移植到另一種數據庫),都會造成系統源碼級的修改[2]。
比這種方法稍進步些的方法是:在業務層與數據庫之間增加數據訪問層,封裝與數據庫相關的各種操作。如此一來,業務類便脫離了SQL語句,系統的整體結構也更為清晰。這也是當前軟件開發過程中的主流方法。但是這種方法仍然不能使面向對象的開發者完全擺脫數據庫的束縛,數據庫發生變動之后,仍然需要改寫和重新編譯數據類。
本文將討論的方法是:在業務層與數據庫之間構建一個持久層,使得業務類需要的數據透明地在數據庫中進行存取,面向對象的開發者似乎根本感覺不到數據庫的存在,只要將需要存取的數據通知持久層,其他的事情都由持久層的內部機制來實現。如果數據庫發生某種變化,持久層則負責對業務層屏蔽這些變化,為業務類提供高度統一的數據訪問模式。O/R Mapping框架工作在業務層和持久機制(本文限定于關系數據庫)之間,它為業務邏輯包裝了數據類的持久化實現,保護應用開發者不受底層變化的影響[3]。使得我們可以在業務層完全專注于問題域,而無需理會繁雜的數據庫操作問題,只需發出簡單的Save,Retrieve,Delete等命令,O/R Mapping框架便自動將對對象的操作映射為對相關的數據表和字段等的操作;對于持久機制而言,它也屏蔽了面向對象的特征,使得數據庫管理員可以專注于數據庫的管理與維護,而不必過分擔心其一舉一動會導致應用程序崩潰。
2 O/R Mapping中類映射到數據表的策略
根據抽象對象與關系數據庫的特性,O/R Mapping通過以下幾個方面實現:類映射到數據表、類屬性映射到數據表列和類之間關系映射為鍵值[4]。對于面向對象的三大特征:封裝、繼承和多態,O/R Mapping都提供了很好的支持。
舉例說明繼承的映射策略:基類Person有兩個子類Student和Teacher,具體關系如圖1所示。
2.1映射整個類層次為單個表
類層次的所有類映射為單個數據庫表,表中保存所有類(基類、子類)的屬性。其中ObjectType字段用來區分類具體的類。該方法的實現如圖2所示。
該方法的優點在于:①實現簡單。②易于增加新類,只需為新增的數據增加新的列即可。③支持多態(對象角色發生變化,或存在多重角色時)。④因為數據都在一個表內,所以訪問速度較快。⑤報表操作實現簡單:表中包含了所有信息。
缺點在于:①增加類層次中的耦合,因為所有的類都直接與表關聯。類層次中任何類的變更會導致表的變更,進而影響到同層次中的其他類。②數據庫空間存在浪費現象。浪費的程度取決于繼承層次的深度[5]。③當角色出現變化時,具體指明它的類別可能很復雜。④隨著類層次的延伸,數據表會快速增大。
對于比較簡單的應用,繼承層次較淺,且角色變換很少時可采用這種策略。
2.2映射每個繼承路徑為單個表
數據庫表包括自身的屬性和繼承的屬性,每個具體的子類包含各自的OID(Object ID),抽象的基類不參與映射。圖3描述了該方法的實現。其中,Person由于是抽象類,未映射成數據庫表;而Student、Teacher類映射為相應的表,它們具有各自的主鍵。
該方法的優點在于:①報表操作實現簡單。表中包含具體子類的所有信息。②訪問單獨的對象的數據時性能良好。
缺點在于:①要修改一個類,不但要修改它映射的表,還需要修改它所有子類映射的表。例如要為Person增加Birthday屬性,就需要在Student和Teacher表中都增加這一列數據。②當角色更改時,如一個Student對象要變為Teacher對象,這時候就需要把數據拷貝到適當的表中,同時可能需要對對象ID重新賦值。③難以在支持多重角色時,保持數據的完整性。例如,難以處理一個既是Student又是Teacher對象的數據。
當角色變換非常少見時,可以采用這種策略。
2.3映射每個類作為單個表
表中包含特定于該類的屬性和OID。類Student的數據存放在Student和Person兩個表中。因此要想取得Student的數據就需要連接這兩個表。圖4描述了該方法的實現。在Student和Teacher表中,PersonOID既是主鍵又是外鍵,用來保存同Person表的聯系。
該方法的優點在于:①這種1∶1映射的方式容易讓人理解。②對多態的支持最好,對于對象可能充當的角色僅需要在相應的表中保存記錄。③修改基類和增加新類的時候,只需要更改和增加數據表即可。④數據量的增長與對象數量的增長是成比例的。
缺點在于:①數據庫中存在大量的表。②由于需要很多的表鏈接操作,訪問數據的效率不甚理想。③除非定義視圖,否則很難生成報表。
當角色變換較頻繁時,需要采用此策略。
3 O/R Mapping在.NET中的實現
對于O/R Mapping中的表和持久化類之間的映射,主要有兩種方式:①單純的持久化類映射。表與持久化類之間的映射是通過硬編碼的方式寫成類,編譯后運行的。這種方式用起來直觀明了,程序員可以控制的部分多,運行速度快。缺點是如果更改表的字段、類型等,需要直接更改類里面的代碼,再編譯后才能運行。②通過XML和持久化類一起來實現映射。持久化類映射出來的是實體類,大部分關于類屬性的類型、長度、是否能修改、是否可以插入,表字段的類型、長度、是否允許為空等,都通過XML文件來表達。表的映射關系需要改動時,只需修改XML文件部分,持久化類不需要改動及重新編譯。現在流行這種方式,它更靈活,耦合性更低。本文將要討論的NHibernate就是屬于這一類。NHibernate是一個基于.NET的O/R映射對象持久庫。它是從Java下的對象/關系(數據庫)持久工具 Hibernate移植過來的。它在.NET下的O/R Mapping領域獲得了較為廣泛的支持。
3.1NHibernate的特征
(1)透明地提供對象與關系數據庫的映射,以統一的接口支持多種數據庫,使得數據庫之間的移植非常方便。
(2)支持的HQL是一種面向對象的查詢語言,它具備繼承、關聯、多態等特性。它也支持一種直觀的、可擴展的條件查詢API,但是不支持原生查詢。
(3)支持本地事務,使用Transaction對象對.NET的事務對象(實現了IDbTransaction接口的對象)進行了包裝。對于長事務目前NHibernate也支持Versioning和Optimistic Locking的實現。
(4)提供了Session Factory和Session來解決線程同步問題。Session Factory是一個線程安全但開銷大的對象,它可被多個線程同時訪問;Session是線程不安全但開銷小的對象,只可被一個線程訪問。這樣NHibernate把需要線程共享的東西放在Session Factory中,不需共享的放在Session中。
(5)提供全部是基于Hashtable的多級緩存機制,以及類似操作系統“元語”的鎖機制,充分考慮了性能和擴展性。
3.2Nhibernate核心架構分析
Session和Session Factory是NHibernate的核心部分。后者維護到持久機制(數據庫)的鏈接并對它們進行管理,同時還保存著所有持久對象的映射信息。Session Factory由Configuration.BuildSessionFactory創建,這個對象一般使用Singleton模式。Session用于將對象持久化,支持數據庫事務,另外還提供了強大的數據加載功能,如圖5所示。
其他對象說明:
IConnectionProvider是鏈接提供者接口,負責與數據進行鏈接;
Dialect是數據庫方言;
CollectionPersister是集合持久化類;
IClassPersister是類持久化接口,定義了基本的CRUD操作;
TransactionFactory是數據庫事務工廠;
IInterceptor是攔截器接口,用于在操作執行時進行一些處理,典型的就是記錄操作日志。
3.3NHibernate實現類映射到數據表策略
用上面舉的例子。實際應用中,像生成數據庫結構、生成標準實體類都是有工具可以利用的,那樣會大大提高開發效率。這里為了說明問題暫不采用。
首先,在數據庫中建立表結構。采用映射每個繼承路徑為單個表的映射策略,建立Student和Teacher兩個表。NHibernate需要把實體類和數據表的映射關系寫在XML格式的Mapping文件當中。針對Student的映射文件如下:
length=\"20\">
length=\"40\"/> 在class標記中指明了實體類及其映射的數據表的名稱,而id標記則指明了數據表的主鍵,這也是NHibernate用來判斷對象唯一性的標志。id中的generator指定了主鍵的生成方式。NHibernate內部附帶了幾種不同的標識符生成器,如數據庫本地的順序生成器、UUID生成、利用Hi/Lo高低位生成模式等,本例采用程序自己指定(Assigned)的方法。property標記指定了實體類的每個屬性映射到數據表的哪一列。 映射文件中可以對多態行為、延遲裝載、動態更新或插入、樂觀鎖定的策略等屬性進行指定,這一切持久化策略的更改都只需要對映射文件作出修改,而應用程序卻不需要變化,使得應用的靈活性和擴展性得到很大的提高。 另外還需要在XML配置文件中添加配置信息: \"NHibernate.Connection.DriverConnectionProvider\" /> value=\"NHibernate.Dialect.MsSql2000Dialect\"/> 在配置文件中,指明了數據鏈接提供者、數據庫語言(以SQL Server 2000為例)、數據鏈接驅動和鏈接字符串。 配置好數據庫鏈接之后,我們就可以開始利用NHibernate工作了。下面以添加一個Student對象為例。 (1)創建一個Configuration對象:Configuration對象能夠解析所有.NET對象和后臺數據庫的映射關系。 Configuration cfg=new Configuration(); cfg.AddAssembly(\"NHibernateSample\"); Configuration對象會搜索裝配件中任何以hbm.xml結尾的文件。還有其他方法加載映射文件,但該方式是最簡單的。 (2)創建一個Session對象:ISession對象提供一個到后臺數據庫的鏈接,ITransaction對象提供一個可以被NHibernate管理的事務。創建會話工廠時,一般來說應該使用一個單例對象來封裝會話工廠。 ISessionFactory factory= cfg.BuildSessionFactory(); ISession session=factory.OpenSession(); ITransaction tran=session.BeginTransaction(); (3)然后創建一個實體類: Student stu=new Student(); stu.Id=\"0001\"; stu.Name=\"Jim Smith\"; stu.Grade=\"03\"; (4)利用Session對象將實體類持久化:session.Save(stu); (5)將事務提交并關閉會話: tran.Commit();session.Close(); 如此一來,類似關于數據庫的CRUD操作都可以轉換成完全面向對象的方式來實現,可以看到,O/R Mapping技術能夠將應用程序邏輯和數據庫結構真正有效地解耦,切實提高系統的可移植性和擴展性,更好地滿足了日后對系統需求的種種未知的變更,使得系統的可維護性也得到了很大的提高。 4結論 O/R Mapping是面向對象分析設計的產物,也是分層設計要解決的問題之一。它的出現有效地填補了關系數據庫理論與面向對象理論之間的鴻溝,為基于數據的種種應用的開發提供了一種穩定、高效、擴展性極佳的解決方案。 在當今的技術條件下,完全的面向對象的數據庫產品還有重大技術難題,因而技術成熟的關系數據庫依然是企業應用的首選。像NHibernate這類的對象關系映射框架使我們從開發數據訪問層的煩瑣又容易出錯的勞動中解脫出來,使得應用開發人員根本無須關心持久化的問題,是配合關系數據庫與面向對象開發語言開發企業應用的極佳工具。在可以預見的將來,O/R Mapping技術將在.NET領域中發揮更為重要的作用。 參考文獻: [1]Scott W Ambler. Mapping Objects to Relational Database[EB/OL]. http://www.ambysoft.com/essays/mappingObjects.html, 2005-06-21. [2]Scott W Ambler. A Design of a Robust Persistence Layer for Relational Databases[EB/OL]. http://www.ambysoft.com/ downloads/persistencelayer.pdf, 2005-06-21. [3]Joseph W Yoder, et al. Connecting Business Objects to Relational Database[EB/OL]. http://www.joeyoder.com/~yoder/papers/patterns/PersistentObject/Persista.pdf, 2005-05-09. [4]何錚,陳志剛.對象/關系映射框架的研究與應用[J].計算機工程與應用,2003,39(26): 188-191. [5]Wolfgang Keller. Mapping Objects to Tables: A Pattern Language[EB/OL]. http://www.objectarchitects.de/Object Architects/papers/Published/ZippedPapers/mappings04.pdf, 2005-05-09. 作者簡介:孫棟海(1980-),男,碩士生,研究方向為數據庫技術;宋順林(1947-),男,教授,研究方向為計算機圖形學、軟件工程、計算機支持協同設計。 注:本文中所涉及到的圖表、注解、公式等內容請以PDF格式閱讀原文。