摘? 要:文章論述了直接使用數(shù)據(jù)庫程序應用接口的不足并對當前流行的數(shù)據(jù)持久化框架技術特點進行了分析。結合項目的具體需求,參考當前已有的數(shù)據(jù)持久化框架的設計思路給出一種利用自定義屬性和反射技術實現(xiàn)對象關系映射功能與數(shù)據(jù)本地持久化的軟件框架的設計與實現(xiàn),該框架除實現(xiàn)對象關系映射功能外,對項目所需數(shù)據(jù)關聯(lián)關系的體現(xiàn)、數(shù)據(jù)的快速查找與本地持久化等功能均有較好的支持。
關鍵詞:.NET;自定義屬性;反射;數(shù)據(jù)持久化;XML;NoSQL
中圖分類號:TP311? 文獻標識碼:A? 文章編號:2096-4706(2023)17-0027-05
Design and Implementation of a Agile Data Persistence Framework under the .NET Environment
XIAO Zhiyong
(The 713th Search Institute of CSSC, Zhengzhou? 450015, China)
Abstract: This paper describes the shortage of using database API directly and analyzes the current popular data persistence framework technical characteristics. Combined with the specific requirements of the project, referring to the design mentalities of the current existing data persistence framework, this paper gives a kind of design and implementation of software framework by using custom attributes and reflection technology to achieve the object relationship mapping function and data local persistence. In addition to realizing the object relationship mapping function, this framework provides convenient support for the embodiment of data association required by the project, rapid data search and local persistence and other functions.
Keywords: .NET; custom attribute; reflection; data persistence; XML; NoSQL
0? 引? 言
ORM(Object Relational Mapping)框架通過面向對象中的類與類之間的所屬關系表示關系型數(shù)據(jù)庫中的數(shù)據(jù)表和表之間依賴關系,是一種只需通過處理相關類對象即可對數(shù)據(jù)庫中的特定數(shù)據(jù)進行操作[1]的數(shù)據(jù)持久化軟件框架。ORM框架為程序操作數(shù)據(jù)庫數(shù)據(jù)提供了一種便捷的方法[2],也是開發(fā)者解決面向對象開發(fā)與數(shù)據(jù)庫之間的匹配常用的技術手段[3]。
現(xiàn)有ORM框架主要有Hibernate[4,5]、Mybati[6]等,但框架自身在項目開發(fā)過程中的應用卻引入了諸如:對使用者沒有完全屏蔽數(shù)據(jù)庫差異、框架本身邏輯結構與機制復雜較難掌握、數(shù)據(jù)訪問性能不佳以及框架對數(shù)據(jù)本地文件方式持久化需求支持不足等問題。
本文以.NET[7]框架為基礎實現(xiàn)了一個敏捷的數(shù)據(jù)持久化框架,框架本身通過采用ORM技術在屏蔽底層數(shù)據(jù)庫差異的同時兼顧數(shù)據(jù)的查找效率并利用基于XML的序列化和反序列化方法完成數(shù)據(jù)的本地持久化功能[8,9]。
1? ORM框架的目標與設計思路
1.1? 主要設計目標
根據(jù)項目實際需求,當前設計的ORM框架應具備以下特點:
1)約定優(yōu)于配置(convention over configuration),數(shù)據(jù)模型自身不能引入其他配置信息;
2)應充分考慮通過數(shù)據(jù)模型展示數(shù)據(jù)間關系的直觀性;
3)在數(shù)據(jù)組織上應考慮查找效率;
4)應支持數(shù)據(jù)的本地持久化需求;
5)操作數(shù)據(jù)的邏輯應盡可能復用,提高軟件開發(fā)生產(chǎn)率、降低代碼規(guī)模。
1.2? 設計思路
數(shù)據(jù)庫訪問框架均支持從數(shù)據(jù)庫當中提取數(shù)據(jù)然后生成對應的數(shù)據(jù)集合的功能。應用程序可以很容易地通過框架提供的數(shù)據(jù)訪問功能接口讀取數(shù)據(jù)庫中指定的數(shù)據(jù)集合。
但反過來,當某個描述數(shù)據(jù)庫表的數(shù)據(jù)集合或該集合中的數(shù)據(jù)元素(即數(shù)據(jù)表中的記錄)被修改后,由于該集合或該集合中的元素中沒有包含除數(shù)據(jù)內(nèi)容以外的其他數(shù)據(jù)庫相關信息,因此對該集合或該集合中元素進行的修改無法直接被保存到數(shù)據(jù)庫對應的表中,相關操作均需在軟件業(yè)務層面給予維護,增加了系統(tǒng)業(yè)務層的邏輯復雜性。應用程序與數(shù)據(jù)庫與間的數(shù)據(jù)交互如圖1所示。
屬性是一種向類型添加信息并影響類型行為的方法[10],它是面向對象特有的RTTI(運行時類型信息)功能的擴展。用戶可以在類的定義過程中通過添加自定義屬性把一些附帶信息標識在該類中(這些包含自定義屬性的類定義下文稱為“數(shù)據(jù)模型”),在使用數(shù)據(jù)模型時利用反射機制可以讀取定義的用戶自定義屬性中包含的內(nèi)容作為業(yè)務邏輯的輸入信息。
針對本數(shù)據(jù)持久化框架中的ORM數(shù)據(jù)模型,如圖2所示:通過自定義屬性,可以將數(shù)據(jù)庫相關表定義信息以自定義屬性的方式包含在相應數(shù)據(jù)模型中。當對應的數(shù)據(jù)信息出現(xiàn)更改時,由專門的數(shù)據(jù)解析層將發(fā)生的數(shù)據(jù)更改結合該信息附帶的數(shù)據(jù)庫定義信息生成對應的數(shù)據(jù)庫訪問語句,提交數(shù)據(jù)庫完成對涉及內(nèi)容的更改。
同時,本文所述框架進一步利用自定義屬性的特性結合基于XML的序列化與反序列化技術,以文件讀寫的方式,可完成數(shù)據(jù)的本地持久化功能。
綜上所述,與數(shù)據(jù)庫表對應“數(shù)據(jù)模型”的自定義屬性添加方式(位置)和內(nèi)容是本數(shù)據(jù)持久化方案的關鍵,它直接關系到數(shù)據(jù)解析層的設計與數(shù)據(jù)持久化功能的實現(xiàn)方式,同時自定義屬性添加位置與描述內(nèi)容也是該數(shù)據(jù)持久化框架與其他采用類似解決方案的數(shù)據(jù)持久化框架的區(qū)別所在。如在文獻[11]中的論述中也提出了采用自定義屬性來對數(shù)據(jù)庫表定義進行映射的思路,但其自定義屬性的目的是借助自定義屬性生成NHibernate[12]框架運行所需特定數(shù)據(jù)庫配置類,所述自定義屬性的定義目的和定義方式與本文所述設計理念完全不同。
2? 框架實現(xiàn)
2.1? 數(shù)據(jù)模型的文法定義
本方案確定通過在描述數(shù)據(jù)庫表的類中添加描述數(shù)據(jù)庫表結構的自定義屬性的方式來生成一種包含數(shù)據(jù)庫表結構相關信息的類。
根據(jù)實際需要,當前SQL語言解析層定義了整型、浮點型、字符串、時間日期和字節(jié)流五種數(shù)據(jù)庫數(shù)據(jù)類型,其他數(shù)據(jù)類型可在今后的項目開發(fā)過程中隨需要進行添加?!癉ataBaseAttribute”“TableAttribute”“FieldAttribute”和“IdentityAttribute”均為自定義屬性,在下面文法定義表述中被認為是關鍵字。
數(shù)據(jù)模型數(shù)據(jù)定義部分的文法定義如下(采用Managed C++描述):
[DataBaseAttribute(數(shù)據(jù)庫名稱)]
[TableAttribute(表名稱)]
public ref class 類名稱
{
{[FieldAttribute(列名稱,列別名)] {<主鍵標識>}<數(shù)據(jù)類型> 變量名稱;}
[FieldAttribute(列名稱,列別名)] {<主鍵標識>}<數(shù)據(jù)類型> 變量名稱;
};
〈主鍵標識〉→[IdentityAttribute(SelfIncrease| Ordinary)]
〈數(shù)據(jù)類型〉→int | float | String ^ | DateTime/byte[]
數(shù)據(jù)庫名稱,表名稱,列名稱,列別名,類名稱→〈字符〉﹛〈字符〉 | 〈數(shù)字〉﹜
〈數(shù)字〉→0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ﹛〈數(shù)字〉﹜
〈字符〉→A | B | ‥ | Y | Z | a | b | ‥ | y | z | ﹛〈字符〉﹜
按上述形式定義的數(shù)據(jù)模型中包含了數(shù)據(jù)庫表結構中用于生成數(shù)據(jù)操作語句(SQL)的全部信息。將這些數(shù)據(jù)模型的實例作為圖2所示數(shù)據(jù)解析層的輸入,實例附帶的自定義屬性信息(即數(shù)據(jù)庫表結構信息)和實例自身的變量取值可滿足生成SQL語句的需要,通過生成的SQL語句可以對相應數(shù)據(jù)庫中的內(nèi)容進行操作。
在實際的實施過程中,通過編制相關的代碼自動生成工具,讀取數(shù)據(jù)庫中相關表的結構定義信息(即數(shù)據(jù)庫中的數(shù)據(jù)字典),可自動完成數(shù)據(jù)模型的代碼編制工作。
2.2? 數(shù)據(jù)關聯(lián)關系的描述
關系型數(shù)據(jù)庫的基本原理是集合論,通過定義二維表和使用笛卡兒乘積描述二維表之間的關系來完成設計[13]。數(shù)據(jù)間的關系通過二維表來體現(xiàn),可歸納為:“一對一”“一對多”和“多對多”三種情況。
從面向對象的角度看,對象之間的聚合關系也可歸納為上述三種情況。在工程實現(xiàn)層面,一般將復雜的“多對多”關系通過解耦變?yōu)閮蓚€“一對多”的關系給予簡化。同時,從集合的角度看,“一對一”的關系可以被認為是“一對多”關系的特化,因此在實現(xiàn)層面的設計中,只需解決“一對多”數(shù)據(jù)關系的映射即可較好地描述數(shù)據(jù)間的關系。
關系型數(shù)據(jù)庫中,通過二維表之間的“主-外鍵”定義來表現(xiàn)的“一對多”數(shù)據(jù)關系,綜上所述,該數(shù)據(jù)關系可以通過定義“主-外鍵”涉及的數(shù)據(jù)模型類之間的聚合關系來體現(xiàn)。
上述關系在數(shù)據(jù)庫設計層面、數(shù)據(jù)模型定義層面和代碼實現(xiàn)層面的示例如圖3所示。在數(shù)據(jù)庫設計層面,通過主-外鍵關系可以確認TableB為TabelA的從表;在數(shù)據(jù)模型定義層面,表TabelA對應數(shù)據(jù)模型與表TableB對應的數(shù)據(jù)模型之間建立“一對多”聚合關系;在代碼實現(xiàn)層面,表TableA對應的數(shù)據(jù)模型類提供一個存放TableB數(shù)據(jù)模型類實例的集合屬性,表TableB對應的數(shù)據(jù)模型類提供一個存放TableA數(shù)據(jù)模型類實例的屬性。
在實際實現(xiàn)過程中,同樣可通過編制代碼自動生成工具,讀取數(shù)據(jù)字典中的各數(shù)據(jù)表之間的“主-外鍵關系”定義完成相關關系屬性的獲取,以及數(shù)據(jù)在增加、刪除、修改時數(shù)據(jù)關聯(lián)關系自動維護機制等功能的代碼編制工作。
2.3? NoSQL的數(shù)據(jù)組織方式與數(shù)據(jù)本地持久化實現(xiàn)
系統(tǒng)在運行時為了提高數(shù)據(jù)的響應速率、擴展性以及分布式處理的需求,需要在隨機存儲器(RAM)中構造復雜的對象實例,并且快速地訪問這些對象實例。由于RAM是臨時性的存儲器,如果需要保存系統(tǒng)執(zhí)行現(xiàn)場,必須使這些復雜對象的生存期跨越程序的執(zhí)行期,因此借助外部存儲器對這些數(shù)據(jù)進行持久化[14]操作就成為必然的要求。
綜合考慮上述需求,框架借鑒典型內(nèi)存數(shù)據(jù)庫(MMDB)Redis[15]中對數(shù)據(jù)組織的方式,將當前數(shù)據(jù)庫中每個表涉及的數(shù)據(jù)在內(nèi)存中以行式鍵值模型[16]的方式進行組織,以此提高數(shù)據(jù)查詢的響應速率并滿足擴展性和分布式處理的需求。
行式鍵值模型的核心是將原關系數(shù)據(jù)庫表中的每行數(shù)據(jù)轉變?yōu)橐粋€(或若干個)Hash結構,形成一個Key-Value映射集合。利用Key去定位Value在理想狀態(tài)下是一個復雜度為O(1)的操作。在本框架的數(shù)據(jù)組織方案中,Key值不用經(jīng)過編碼的字符串表示而是將數(shù)據(jù)表中的主鍵列進行包裝生成一個對應的“鍵值類”,Value值為數(shù)據(jù)表對應數(shù)據(jù)模型的實例,實例中每個字段是對應數(shù)據(jù)的列,其取值為對應列的值。通過重新定義“鍵值類”的Hash值生成機制,確保其Hash算法的正確與高效,進而確保查詢效率。數(shù)據(jù)處理和組織過程如圖4所示。
由于XML遵循嚴格語法規(guī)范,具有擴展性好、數(shù)據(jù)共享與重用簡單、便于跨平臺傳遞等優(yōu)點,因此本框架的數(shù)據(jù)本地持久化方案采用XML的組織方式實現(xiàn)。
由于數(shù)據(jù)在內(nèi)存中采用行式鍵值模型的方式進行組織,數(shù)據(jù)容器本身序列化的思路是:容器內(nèi)的每一個“Key-Value”元素定義成一個名稱為“item”的節(jié)點;對應的Key值作為“item”節(jié)點的下一級節(jié)點其名稱定義為“key”;對應的Value值同樣作為“item”節(jié)點的下一級節(jié)點其名稱定義為“value”。同時,數(shù)據(jù)容器中存放Key和Value的實例由于都是繼承自.NET框架下的object類,因此只需在類定義時標注上框架預定義的自定義屬性標簽即可完成上述對應數(shù)據(jù)實例的序列化與反序列化功能[17]。
3? 框架實現(xiàn)說明
3.1? ORM驅動層的泛型化實現(xiàn)
泛型是C#編程語言的一種特性,通過使用該特性涉及的泛型類、泛型函數(shù)、泛型代理(事件)和泛型接口等元素進行功能實現(xiàn),使得程序具有更高的抽象度,以此為基礎可顯著提高代碼的復用程度。
泛型編程技術為實現(xiàn)通用的ORM驅動層和數(shù)據(jù)的本地持久化功能提供了高效可用的技術手段,其實現(xiàn)的各功能模塊關系如圖5所示。
圖中,AbstractDao和Dal類是對不同類型數(shù)據(jù)庫數(shù)據(jù)訪問方式的抽象表述;OracleDal是當前支持的Oracle數(shù)據(jù)庫的ORM驅動層的具體實現(xiàn),其內(nèi)部主要數(shù)據(jù)操作功能函數(shù)采用了泛型函數(shù)的方式進行定義與實現(xiàn);TransactionManager用于實現(xiàn)數(shù)據(jù)庫數(shù)據(jù)操作的原子性和一致性功能;GenericManager
3.2? 框架各功能模塊邏輯關系
框架各功能部分的邏輯關系如圖6所示。整個框架是一個分層Layer[18]模式的應用,其中的數(shù)據(jù)庫訪問控制是一個Singleton[19]模式的應用。
系統(tǒng)通過調用數(shù)據(jù)管理層的相關功能,完成對數(shù)據(jù)的增、刪、改、查等操作;數(shù)據(jù)管理層對系統(tǒng)應用屏蔽了描述數(shù)據(jù)庫表的集合實例,相關的數(shù)據(jù)操作通過SQL語言解析層被最終反映到數(shù)據(jù)庫當中。數(shù)據(jù)庫中的數(shù)據(jù)通過數(shù)據(jù)集合生成模塊按數(shù)據(jù)持久化層對數(shù)據(jù)的相關要求(數(shù)據(jù)模型中添加的各種數(shù)據(jù)庫相關自定義屬性)進行打包,生成描述數(shù)據(jù)庫表數(shù)據(jù)集合實例。配置模塊中存放了各層直接需要共享的接口定義,枚舉類型等公共信息。通過底層SQL語言解析層和XML的序列化反序列化功能模塊,框架可以同時實現(xiàn)對數(shù)據(jù)在遠端和本地的持久化功能。
4? 結? 論
本框架是一個功能齊全的基于ORM設計思想的數(shù)據(jù)持久化框架,具有數(shù)據(jù)模型定義簡單、使用方便的優(yōu)點,在處理“一對多”表關系時非常便捷,適用于以關系型數(shù)據(jù)庫為中心同時又要求具備較高的數(shù)據(jù)查詢響應速率對可擴展性、分布式處理以及數(shù)據(jù)本地持久化有相應需求的應用。
設計與實現(xiàn)過程中,通過遵循基于Layer模式的Class-Type體系結構,各層之間的耦合度較低,整個框架易于擴展、維護。
在基金項目所屬算法仿真平臺的研制過程中,通過應用該框架,項目所需數(shù)據(jù)之間復雜依賴關系得到較好體現(xiàn)與維護;算法驗證平臺相關數(shù)據(jù)結構設計與定義實現(xiàn)之間的迭代周期明顯縮短;NoSQL的數(shù)據(jù)表示方式對該算法驗證平臺的分布式運行起到較好的支持作用。
本框架涉及數(shù)據(jù)模型定義、數(shù)據(jù)關系定義、數(shù)據(jù)的NoSQL組織方式與數(shù)據(jù)持久化方法等設計思想不僅可在.NET平臺下進行實現(xiàn),通過利用Qt框架中的MetaObject以及C++語言的模板編程等技術,上述設計思想可基于Qt框架進行實現(xiàn)。
參考文獻:
[1] 丁昊志.對象關系映射模型研究 [D].北京:華北電力大學,2006.
[2] 梁文菲,黃厚寬.對象/關系映射技術與面向對象數(shù)據(jù)庫技術比較分析 [J].中國科技信息,2006(21):154-156.
[3] AMBLER S W. Mapping objects to relational databases:O/R mapping in detail [EB/OL].[2023-01-26].http://www.agiledata.org/essays/mappingObjects.html.
[4] JOHNSON R,HOELLER J. Expert One-on-One J2EE Development without EJB [M].JavaEye,譯.北京:電子工業(yè)出版社,2005.
[5] GAVIN K,CHRISTIAN B. Hibernate 實戰(zhàn):第2版 [M].蒲成,譯.北京:清華大學出版社,2016.
[6] 陳永政,張正龍.Java EE 框架技術 Spring-MVC+Spring+MyBatis [M].西安:西安電子科技大學出版社,2017:182-204.
[7] Microsoft. .NET Framework 開發(fā)人員指南:.NET Framework 概述 [EB/OL].[2023-01-26].https://learn.microsoft.com/zh-cn/dotnet/framework/get-started/overview.
[8] Microsoft. .NET Framework 開發(fā)人員指南:編寫自定義屬性 [EB/OL].[2023-01-26].https://docs.microsoft.com/zh-cn/dotnet/standard/attributes/writing-custom-attributes.
[9] Microsoft. NET Framework 開發(fā)人員指南:反射 [EB/OL].[2023-01-26].https://docs.microsoft.com/zh-cn/dotnet/framework/reflection-and-codedom/reflection.
[10] L?WY J. .NET組件程序設計:第2版 [M].劉如鴻,譯.北京:電子工業(yè)出版社,2007 544-545.
[11] 鐘云.對象關系映射(ORM)的研究與基于C#.NET的部分實現(xiàn) [D].上海:上海海事大學,2006.
[12] NHibernate. The object-relational mapper for .NET [EB/OL].[2023-01-26].https://www.nhibernate.info/.
[13] 薩師煊.數(shù)據(jù)庫系統(tǒng)概論:第3版 [M].北京:高等教育出版社,2003:45-82.
[14] 俞建,張燎軍.數(shù)據(jù)庫訪問技術研究 [J].計算機與現(xiàn)代化,2004(10):29-31.
[15] redis. Documentation [EB/OL].[2023-01-26].https://redis.io/docs/.
[16] 張俊,廖雪花,余旭玲,等.關系型數(shù)據(jù)庫內(nèi)存化存儲模型研究 [J].計算機工程與應用,2021,57(19):123-128.
[17] Microsoft. .NET Framework中的對象序列化 [EB/OL].[2023-01-26].https://learn.microsoft.com/zh-cn/previous-versions/dotnet/articles/ms973893(v=msdn.10).
[18] BUSCHMANN F,MEUNIER R,ROHNERT R,等.面向模式的軟件體系結構卷1:模式系統(tǒng) [M].賁可榮,郭福亮,趙皚,等譯.北京:機械工業(yè)出版社,2003:18-19.
[19] GAMMA E,HELM E,JOHNSON R,等.設計模式-可復用面向對象軟件的基礎 [M].李英軍,馬曉星,蔡敏,等譯.北京:機械工業(yè)出版社,2000:84-89.
作者簡介:肖志勇(1977—),男,回族,河南新鄉(xiāng)人,高級工程師,工學碩士,研究方向:人工智能與分布式計算。