摘? 要:文章論述了直接使用數(shù)據(jù)庫程序應(yīng)用接口的不足并對當(dāng)前流行的數(shù)據(jù)持久化框架技術(shù)特點進行了分析。結(jié)合項目的具體需求,參考當(dāng)前已有的數(shù)據(jù)持久化框架的設(shè)計思路給出一種利用自定義屬性和反射技術(shù)實現(xiàn)對象關(guān)系映射功能與數(shù)據(jù)本地持久化的軟件框架的設(shè)計與實現(xiàn),該框架除實現(xiàn)對象關(guān)系映射功能外,對項目所需數(shù)據(jù)關(guān)聯(lián)關(guān)系的體現(xiàn)、數(shù)據(jù)的快速查找與本地持久化等功能均有較好的支持。
關(guān)鍵詞:.NET;自定義屬性;反射;數(shù)據(jù)持久化;XML;NoSQL
中圖分類號:TP311? 文獻標(biāo)識碼: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)框架通過面向?qū)ο笾械念惻c類之間的所屬關(guān)系表示關(guān)系型數(shù)據(jù)庫中的數(shù)據(jù)表和表之間依賴關(guān)系,是一種只需通過處理相關(guān)類對象即可對數(shù)據(jù)庫中的特定數(shù)據(jù)進行操作[1]的數(shù)據(jù)持久化軟件框架。ORM框架為程序操作數(shù)據(jù)庫數(shù)據(jù)提供了一種便捷的方法[2],也是開發(fā)者解決面向?qū)ο箝_發(fā)與數(shù)據(jù)庫之間的匹配常用的技術(shù)手段[3]。
現(xiàn)有ORM框架主要有Hibernate[4,5]、Mybati[6]等,但框架自身在項目開發(fā)過程中的應(yīng)用卻引入了諸如:對使用者沒有完全屏蔽數(shù)據(jù)庫差異、框架本身邏輯結(jié)構(gòu)與機制復(fù)雜較難掌握、數(shù)據(jù)訪問性能不佳以及框架對數(shù)據(jù)本地文件方式持久化需求支持不足等問題。
本文以.NET[7]框架為基礎(chǔ)實現(xiàn)了一個敏捷的數(shù)據(jù)持久化框架,框架本身通過采用ORM技術(shù)在屏蔽底層數(shù)據(jù)庫差異的同時兼顧數(shù)據(jù)的查找效率并利用基于XML的序列化和反序列化方法完成數(shù)據(jù)的本地持久化功能[8,9]。
1? ORM框架的目標(biāo)與設(shè)計思路
1.1? 主要設(shè)計目標(biāo)
根據(jù)項目實際需求,當(dāng)前設(shè)計的ORM框架應(yīng)具備以下特點:
1)約定優(yōu)于配置(convention over configuration),數(shù)據(jù)模型自身不能引入其他配置信息;
2)應(yīng)充分考慮通過數(shù)據(jù)模型展示數(shù)據(jù)間關(guān)系的直觀性;
3)在數(shù)據(jù)組織上應(yīng)考慮查找效率;
4)應(yīng)支持?jǐn)?shù)據(jù)的本地持久化需求;
5)操作數(shù)據(jù)的邏輯應(yīng)盡可能復(fù)用,提高軟件開發(fā)生產(chǎn)率、降低代碼規(guī)模。
1.2? 設(shè)計思路
數(shù)據(jù)庫訪問框架均支持從數(shù)據(jù)庫當(dāng)中提取數(shù)據(jù)然后生成對應(yīng)的數(shù)據(jù)集合的功能。應(yīng)用程序可以很容易地通過框架提供的數(shù)據(jù)訪問功能接口讀取數(shù)據(jù)庫中指定的數(shù)據(jù)集合。
但反過來,當(dāng)某個描述數(shù)據(jù)庫表的數(shù)據(jù)集合或該集合中的數(shù)據(jù)元素(即數(shù)據(jù)表中的記錄)被修改后,由于該集合或該集合中的元素中沒有包含除數(shù)據(jù)內(nèi)容以外的其他數(shù)據(jù)庫相關(guān)信息,因此對該集合或該集合中元素進行的修改無法直接被保存到數(shù)據(jù)庫對應(yīng)的表中,相關(guān)操作均需在軟件業(yè)務(wù)層面給予維護,增加了系統(tǒng)業(yè)務(wù)層的邏輯復(fù)雜性。應(yīng)用程序與數(shù)據(jù)庫與間的數(shù)據(jù)交互如圖1所示。
屬性是一種向類型添加信息并影響類型行為的方法[10],它是面向?qū)ο筇赜械腞TTI(運行時類型信息)功能的擴展。用戶可以在類的定義過程中通過添加自定義屬性把一些附帶信息標(biāo)識在該類中(這些包含自定義屬性的類定義下文稱為“數(shù)據(jù)模型”),在使用數(shù)據(jù)模型時利用反射機制可以讀取定義的用戶自定義屬性中包含的內(nèi)容作為業(yè)務(wù)邏輯的輸入信息。
針對本數(shù)據(jù)持久化框架中的ORM數(shù)據(jù)模型,如圖2所示:通過自定義屬性,可以將數(shù)據(jù)庫相關(guān)表定義信息以自定義屬性的方式包含在相應(yīng)數(shù)據(jù)模型中。當(dāng)對應(yīng)的數(shù)據(jù)信息出現(xiàn)更改時,由專門的數(shù)據(jù)解析層將發(fā)生的數(shù)據(jù)更改結(jié)合該信息附帶的數(shù)據(jù)庫定義信息生成對應(yīng)的數(shù)據(jù)庫訪問語句,提交數(shù)據(jù)庫完成對涉及內(nèi)容的更改。
同時,本文所述框架進一步利用自定義屬性的特性結(jié)合基于XML的序列化與反序列化技術(shù),以文件讀寫的方式,可完成數(shù)據(jù)的本地持久化功能。
綜上所述,與數(shù)據(jù)庫表對應(yīng)“數(shù)據(jù)模型”的自定義屬性添加方式(位置)和內(nèi)容是本數(shù)據(jù)持久化方案的關(guān)鍵,它直接關(guān)系到數(shù)據(jù)解析層的設(shè)計與數(shù)據(jù)持久化功能的實現(xiàn)方式,同時自定義屬性添加位置與描述內(nèi)容也是該數(shù)據(jù)持久化框架與其他采用類似解決方案的數(shù)據(jù)持久化框架的區(qū)別所在。如在文獻[11]中的論述中也提出了采用自定義屬性來對數(shù)據(jù)庫表定義進行映射的思路,但其自定義屬性的目的是借助自定義屬性生成NHibernate[12]框架運行所需特定數(shù)據(jù)庫配置類,所述自定義屬性的定義目的和定義方式與本文所述設(shè)計理念完全不同。
2? 框架實現(xiàn)
2.1? 數(shù)據(jù)模型的文法定義
本方案確定通過在描述數(shù)據(jù)庫表的類中添加描述數(shù)據(jù)庫表結(jié)構(gòu)的自定義屬性的方式來生成一種包含數(shù)據(jù)庫表結(jié)構(gòu)相關(guān)信息的類。
根據(jù)實際需要,當(dāng)前SQL語言解析層定義了整型、浮點型、字符串、時間日期和字節(jié)流五種數(shù)據(jù)庫數(shù)據(jù)類型,其他數(shù)據(jù)類型可在今后的項目開發(fā)過程中隨需要進行添加?!癉ataBaseAttribute”“TableAttribute”“FieldAttribute”和“IdentityAttribute”均為自定義屬性,在下面文法定義表述中被認(rèn)為是關(guān)鍵字。
數(shù)據(jù)模型數(shù)據(jù)定義部分的文法定義如下(采用Managed C++描述):
[DataBaseAttribute(數(shù)據(jù)庫名稱)]
[TableAttribute(表名稱)]
public ref class 類名稱
{
{[FieldAttribute(列名稱,列別名)] {<主鍵標(biāo)識>}<數(shù)據(jù)類型> 變量名稱;}
[FieldAttribute(列名稱,列別名)] {<主鍵標(biāo)識>}<數(shù)據(jù)類型> 變量名稱;
};
〈主鍵標(biāo)識〉→[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ù)庫表結(jié)構(gòu)中用于生成數(shù)據(jù)操作語句(SQL)的全部信息。將這些數(shù)據(jù)模型的實例作為圖2所示數(shù)據(jù)解析層的輸入,實例附帶的自定義屬性信息(即數(shù)據(jù)庫表結(jié)構(gòu)信息)和實例自身的變量取值可滿足生成SQL語句的需要,通過生成的SQL語句可以對相應(yīng)數(shù)據(jù)庫中的內(nèi)容進行操作。
在實際的實施過程中,通過編制相關(guān)的代碼自動生成工具,讀取數(shù)據(jù)庫中相關(guān)表的結(jié)構(gòu)定義信息(即數(shù)據(jù)庫中的數(shù)據(jù)字典),可自動完成數(shù)據(jù)模型的代碼編制工作。
2.2? 數(shù)據(jù)關(guān)聯(lián)關(guān)系的描述
關(guān)系型數(shù)據(jù)庫的基本原理是集合論,通過定義二維表和使用笛卡兒乘積描述二維表之間的關(guān)系來完成設(shè)計[13]。數(shù)據(jù)間的關(guān)系通過二維表來體現(xiàn),可歸納為:“一對一”“一對多”和“多對多”三種情況。
從面向?qū)ο蟮慕嵌瓤?,對象之間的聚合關(guān)系也可歸納為上述三種情況。在工程實現(xiàn)層面,一般將復(fù)雜的“多對多”關(guān)系通過解耦變?yōu)閮蓚€“一對多”的關(guān)系給予簡化。同時,從集合的角度看,“一對一”的關(guān)系可以被認(rèn)為是“一對多”關(guān)系的特化,因此在實現(xiàn)層面的設(shè)計中,只需解決“一對多”數(shù)據(jù)關(guān)系的映射即可較好地描述數(shù)據(jù)間的關(guān)系。
關(guān)系型數(shù)據(jù)庫中,通過二維表之間的“主-外鍵”定義來表現(xiàn)的“一對多”數(shù)據(jù)關(guān)系,綜上所述,該數(shù)據(jù)關(guān)系可以通過定義“主-外鍵”涉及的數(shù)據(jù)模型類之間的聚合關(guān)系來體現(xiàn)。
上述關(guān)系在數(shù)據(jù)庫設(shè)計層面、數(shù)據(jù)模型定義層面和代碼實現(xiàn)層面的示例如圖3所示。在數(shù)據(jù)庫設(shè)計層面,通過主-外鍵關(guān)系可以確認(rèn)TableB為TabelA的從表;在數(shù)據(jù)模型定義層面,表TabelA對應(yīng)數(shù)據(jù)模型與表TableB對應(yīng)的數(shù)據(jù)模型之間建立“一對多”聚合關(guān)系;在代碼實現(xiàn)層面,表TableA對應(yīng)的數(shù)據(jù)模型類提供一個存放TableB數(shù)據(jù)模型類實例的集合屬性,表TableB對應(yīng)的數(shù)據(jù)模型類提供一個存放TableA數(shù)據(jù)模型類實例的屬性。
在實際實現(xiàn)過程中,同樣可通過編制代碼自動生成工具,讀取數(shù)據(jù)字典中的各數(shù)據(jù)表之間的“主-外鍵關(guān)系”定義完成相關(guān)關(guān)系屬性的獲取,以及數(shù)據(jù)在增加、刪除、修改時數(shù)據(jù)關(guān)聯(lián)關(guān)系自動維護機制等功能的代碼編制工作。
2.3? NoSQL的數(shù)據(jù)組織方式與數(shù)據(jù)本地持久化實現(xiàn)
系統(tǒng)在運行時為了提高數(shù)據(jù)的響應(yīng)速率、擴展性以及分布式處理的需求,需要在隨機存儲器(RAM)中構(gòu)造復(fù)雜的對象實例,并且快速地訪問這些對象實例。由于RAM是臨時性的存儲器,如果需要保存系統(tǒng)執(zhí)行現(xiàn)場,必須使這些復(fù)雜對象的生存期跨越程序的執(zhí)行期,因此借助外部存儲器對這些數(shù)據(jù)進行持久化[14]操作就成為必然的要求。
綜合考慮上述需求,框架借鑒典型內(nèi)存數(shù)據(jù)庫(MMDB)Redis[15]中對數(shù)據(jù)組織的方式,將當(dāng)前數(shù)據(jù)庫中每個表涉及的數(shù)據(jù)在內(nèi)存中以行式鍵值模型[16]的方式進行組織,以此提高數(shù)據(jù)查詢的響應(yīng)速率并滿足擴展性和分布式處理的需求。
行式鍵值模型的核心是將原關(guān)系數(shù)據(jù)庫表中的每行數(shù)據(jù)轉(zhuǎn)變?yōu)橐粋€(或若干個)Hash結(jié)構(gòu),形成一個Key-Value映射集合。利用Key去定位Value在理想狀態(tài)下是一個復(fù)雜度為O(1)的操作。在本框架的數(shù)據(jù)組織方案中,Key值不用經(jīng)過編碼的字符串表示而是將數(shù)據(jù)表中的主鍵列進行包裝生成一個對應(yīng)的“鍵值類”,Value值為數(shù)據(jù)表對應(yīng)數(shù)據(jù)模型的實例,實例中每個字段是對應(yīng)數(shù)據(jù)的列,其取值為對應(yīng)列的值。通過重新定義“鍵值類”的Hash值生成機制,確保其Hash算法的正確與高效,進而確保查詢效率。數(shù)據(jù)處理和組織過程如圖4所示。
由于XML遵循嚴(yán)格語法規(guī)范,具有擴展性好、數(shù)據(jù)共享與重用簡單、便于跨平臺傳遞等優(yōu)點,因此本框架的數(shù)據(jù)本地持久化方案采用XML的組織方式實現(xiàn)。
由于數(shù)據(jù)在內(nèi)存中采用行式鍵值模型的方式進行組織,數(shù)據(jù)容器本身序列化的思路是:容器內(nèi)的每一個“Key-Value”元素定義成一個名稱為“item”的節(jié)點;對應(yīng)的Key值作為“item”節(jié)點的下一級節(jié)點其名稱定義為“key”;對應(yīng)的Value值同樣作為“item”節(jié)點的下一級節(jié)點其名稱定義為“value”。同時,數(shù)據(jù)容器中存放Key和Value的實例由于都是繼承自.NET框架下的object類,因此只需在類定義時標(biāo)注上框架預(yù)定義的自定義屬性標(biāo)簽即可完成上述對應(yīng)數(shù)據(jù)實例的序列化與反序列化功能[17]。
3? 框架實現(xiàn)說明
3.1? ORM驅(qū)動層的泛型化實現(xiàn)
泛型是C#編程語言的一種特性,通過使用該特性涉及的泛型類、泛型函數(shù)、泛型代理(事件)和泛型接口等元素進行功能實現(xiàn),使得程序具有更高的抽象度,以此為基礎(chǔ)可顯著提高代碼的復(fù)用程度。
泛型編程技術(shù)為實現(xiàn)通用的ORM驅(qū)動層和數(shù)據(jù)的本地持久化功能提供了高效可用的技術(shù)手段,其實現(xiàn)的各功能模塊關(guān)系如圖5所示。
圖中,AbstractDao和Dal類是對不同類型數(shù)據(jù)庫數(shù)據(jù)訪問方式的抽象表述;OracleDal是當(dāng)前支持的Oracle數(shù)據(jù)庫的ORM驅(qū)動層的具體實現(xiàn),其內(nèi)部主要數(shù)據(jù)操作功能函數(shù)采用了泛型函數(shù)的方式進行定義與實現(xiàn);TransactionManager用于實現(xiàn)數(shù)據(jù)庫數(shù)據(jù)操作的原子性和一致性功能;GenericManager
3.2? 框架各功能模塊邏輯關(guān)系
框架各功能部分的邏輯關(guān)系如圖6所示。整個框架是一個分層Layer[18]模式的應(yīng)用,其中的數(shù)據(jù)庫訪問控制是一個Singleton[19]模式的應(yīng)用。
系統(tǒng)通過調(diào)用數(shù)據(jù)管理層的相關(guān)功能,完成對數(shù)據(jù)的增、刪、改、查等操作;數(shù)據(jù)管理層對系統(tǒng)應(yīng)用屏蔽了描述數(shù)據(jù)庫表的集合實例,相關(guān)的數(shù)據(jù)操作通過SQL語言解析層被最終反映到數(shù)據(jù)庫當(dāng)中。數(shù)據(jù)庫中的數(shù)據(jù)通過數(shù)據(jù)集合生成模塊按數(shù)據(jù)持久化層對數(shù)據(jù)的相關(guān)要求(數(shù)據(jù)模型中添加的各種數(shù)據(jù)庫相關(guān)自定義屬性)進行打包,生成描述數(shù)據(jù)庫表數(shù)據(jù)集合實例。配置模塊中存放了各層直接需要共享的接口定義,枚舉類型等公共信息。通過底層SQL語言解析層和XML的序列化反序列化功能模塊,框架可以同時實現(xiàn)對數(shù)據(jù)在遠(yuǎn)端和本地的持久化功能。
4? 結(jié)? 論
本框架是一個功能齊全的基于ORM設(shè)計思想的數(shù)據(jù)持久化框架,具有數(shù)據(jù)模型定義簡單、使用方便的優(yōu)點,在處理“一對多”表關(guān)系時非常便捷,適用于以關(guān)系型數(shù)據(jù)庫為中心同時又要求具備較高的數(shù)據(jù)查詢響應(yīng)速率對可擴展性、分布式處理以及數(shù)據(jù)本地持久化有相應(yīng)需求的應(yīng)用。
設(shè)計與實現(xiàn)過程中,通過遵循基于Layer模式的Class-Type體系結(jié)構(gòu),各層之間的耦合度較低,整個框架易于擴展、維護。
在基金項目所屬算法仿真平臺的研制過程中,通過應(yīng)用該框架,項目所需數(shù)據(jù)之間復(fù)雜依賴關(guān)系得到較好體現(xiàn)與維護;算法驗證平臺相關(guān)數(shù)據(jù)結(jié)構(gòu)設(shè)計與定義實現(xiàn)之間的迭代周期明顯縮短;NoSQL的數(shù)據(jù)表示方式對該算法驗證平臺的分布式運行起到較好的支持作用。
本框架涉及數(shù)據(jù)模型定義、數(shù)據(jù)關(guān)系定義、數(shù)據(jù)的NoSQL組織方式與數(shù)據(jù)持久化方法等設(shè)計思想不僅可在.NET平臺下進行實現(xiàn),通過利用Qt框架中的MetaObject以及C++語言的模板編程等技術(shù),上述設(shè)計思想可基于Qt框架進行實現(xiàn)。
參考文獻:
[1] 丁昊志.對象關(guān)系映射模型研究 [D].北京:華北電力大學(xué),2006.
[2] 梁文菲,黃厚寬.對象/關(guān)系映射技術(shù)與面向?qū)ο髷?shù)據(jù)庫技術(shù)比較分析 [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].蒲成,譯.北京:清華大學(xué)出版社,2016.
[6] 陳永政,張正龍.Java EE 框架技術(shù) Spring-MVC+Spring+MyBatis [M].西安:西安電子科技大學(xué)出版社,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組件程序設(shè)計:第2版 [M].劉如鴻,譯.北京:電子工業(yè)出版社,2007 544-545.
[11] 鐘云.對象關(guān)系映射(ORM)的研究與基于C#.NET的部分實現(xiàn) [D].上海:上海海事大學(xué),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ù)庫訪問技術(shù)研究 [J].計算機與現(xiàn)代化,2004(10):29-31.
[15] redis. Documentation [EB/OL].[2023-01-26].https://redis.io/docs/.
[16] 張俊,廖雪花,余旭玲,等.關(guān)系型數(shù)據(jù)庫內(nèi)存化存儲模型研究 [J].計算機工程與應(yīng)用,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,等.面向模式的軟件體系結(jié)構(gòu)卷1:模式系統(tǒng) [M].賁可榮,郭福亮,趙皚,等譯.北京:機械工業(yè)出版社,2003:18-19.
[19] GAMMA E,HELM E,JOHNSON R,等.設(shè)計模式-可復(fù)用面向?qū)ο筌浖幕A(chǔ) [M].李英軍,馬曉星,蔡敏,等譯.北京:機械工業(yè)出版社,2000:84-89.
作者簡介:肖志勇(1977—),男,回族,河南新鄉(xiāng)人,高級工程師,工學(xué)碩士,研究方向:人工智能與分布式計算。