摘要
在面向?qū)ο蠼F陂g(OOA)最難回答的問(wèn)題是,何時(shí)使用聚合,何時(shí)使用關(guān)聯(lián)。性能和靈活性的權(quán)衡將會(huì)影響到這個(gè)問(wèn)題的答案。你可以使用Single Table Aggregation。這是一種最自然的聚合映射方式。你也可以使用Foreign Key Aggregation,它常常用于處理1:n聚合的映射,我們將在Foreign Key Aggregation的相關(guān)章節(jié)中討論它。(2002-08-20 12:28:18)
By axing
聚合映射的模式
在面向?qū)ο蠼F陂g(OOA)最難回答的問(wèn)題是,何時(shí)使用聚合,何時(shí)使用關(guān)聯(lián)。性能和靈活性的權(quán)衡將會(huì)影響到這個(gè)問(wèn)題的答案。你可以使用Single Table Aggregation。這是一種最自然的聚合映射方式。你也可以使用Foreign Key Aggregation,它常常用于處理1:n聚合的映射,我們將在Foreign Key Aggregation的相關(guān)章節(jié)中討論它。
模式:Single Table Aggregation
摘要:
該模式展示了如何通過(guò)把所有的聚合的對(duì)象屬性集成到單個(gè)的表中的方法把聚合映射到一個(gè)關(guān)系數(shù)據(jù)模型。
示例:
考慮下列的對(duì)象模型:
圖1.一個(gè)AddressType,為其它的對(duì)象所聚合。
問(wèn)題:
如何將聚合映射到關(guān)系表中?
約束:
- 性能:為了得到最佳的性能,該方案應(yīng)該在一次的數(shù)據(jù)庫(kù)訪問(wèn)中,不用Join操作獲取一個(gè)對(duì)象。數(shù)據(jù)庫(kù)訪問(wèn)應(yīng)該只獲取最少的頁(yè)面,以節(jié)省IO帶寬。
- 可維護(hù)性:為了獲得最佳的可維護(hù)性,那些為多個(gè)對(duì)象所聚合的聚合類型,應(yīng)該映射到一組表中,而不是分散到物理數(shù)據(jù)模型的各個(gè)點(diǎn)上。在數(shù)據(jù)模型層次上實(shí)行標(biāo)準(zhǔn)化,這樣可以使維護(hù)簡(jiǎn)單。
- 數(shù)據(jù)庫(kù)的一致性:聚合意味著被聚合對(duì)象的生命周期和需要聚合的對(duì)象的生命周期是相互耦合的。這一點(diǎn)需要由數(shù)據(jù)庫(kù)或應(yīng)用程序代碼來(lái)保證。
解決方案:
把被聚合對(duì)象的屬性和使用聚合對(duì)象的屬性放在同一張表中。
結(jié)構(gòu):
使用聚合的對(duì)象被轉(zhuǎn)換為物理數(shù)據(jù)模型的一張表中,被聚合對(duì)象的數(shù)據(jù)集成到該表中。
解決方法示例:
我們?yōu)镃ustomer對(duì)象創(chuàng)建Customer表。InvoiceAddress和DeliveryAddress都集成到Customer表中。
圖2.將一個(gè)被聚合的對(duì)象類型映射到使用聚合的對(duì)象的數(shù)據(jù)庫(kù)表中。
我們使用前綴來(lái)區(qū)分同類的屬性。這有點(diǎn)類似于C++中的命名空間的概念,例如Customer.DeliveryAddress.Street。
結(jié)論:
- 性能:在性能方面,該方案是最佳的,因?yàn)橹恍枰L問(wèn)一張表就能夠獲取一個(gè)帶聚合的對(duì)象,并讀入所有聚合對(duì)象。另一方面,由于聚合對(duì)象的字段的增多,一次讀取將會(huì)增大數(shù)據(jù)庫(kù)讀入的頁(yè)面數(shù),導(dǎo)致IO帶寬的浪費(fèi)。
- 可維護(hù)性和靈活性:如果聚合的對(duì)象類型被多個(gè)對(duì)象所引用,那么將會(huì)降低可維護(hù)性,因?yàn)槊恳淮螌?duì)聚合對(duì)象類型的修改都會(huì)導(dǎo)致對(duì)所有引用聚合對(duì)象的修改。
- 數(shù)據(jù)庫(kù)的一致性:刪除使用聚合的對(duì)象時(shí),聚合對(duì)象將會(huì)自動(dòng)刪除。不需要任何其它的程序或數(shù)據(jù)庫(kù)觸發(fā)器來(lái)控制。
- 特殊查詢:類似查詢數(shù)據(jù)庫(kù)中所有的AddressType對(duì)象之類的查詢,都會(huì)變得很難處理。
實(shí)現(xiàn):
- 命名規(guī)則:需要為聚合的對(duì)象的屬性考慮前綴或其它的命名規(guī)則。在上面的例子中,我們使用屬性名稱的縮寫形式作為前綴。
- 物理數(shù)據(jù)庫(kù)的頁(yè)面大小:將聚合對(duì)象和使用聚合對(duì)象放在同一張表中,在一定程度上彌補(bǔ)了由于對(duì)象的部分屬性存儲(chǔ)在另一個(gè)數(shù)據(jù)庫(kù)頁(yè)面上的性能損失。這種情況下,讀入的是兩個(gè)頁(yè)面,而不是一個(gè)。
變化:
我們已經(jīng)討論了使用聚合對(duì)象類型和聚合對(duì)象類型之間最簡(jiǎn)單的1:1關(guān)系。Foreign Key Association模式描述了兩種對(duì)象類型間1:n的關(guān)系,Overflow Table則展示了在1:n的關(guān)系下避免采用外鍵的技巧。
相關(guān)模式:
Foreign Key Aggregation模式是Single Table Aggregation模式的備選方案。參考Representing Collections in a Relational Database [Bro+96]。當(dāng)應(yīng)用到普通的關(guān)系型數(shù)據(jù)庫(kù)訪問(wèn)層的時(shí)候,還可以對(duì)比Denormalization [Kel+97]。
參考:
《Mainstream Objects》(Ed Yourdon [You+95] )在第21章完整的討論了在建模時(shí)期何時(shí)使用聚合和關(guān)聯(lián)、以及如何使用它們的問(wèn)題。
聚合映射的模式
在面向?qū)ο蠼F陂g(OOA)最難回答的問(wèn)題是,何時(shí)使用聚合,何時(shí)使用關(guān)聯(lián)。性能和靈活性的權(quán)衡將會(huì)影響到這個(gè)問(wèn)題的答案。你可以使用Single Table Aggregation。這是一種最自然的聚合映射方式。你也可以使用Foreign Key Aggregation,它常常用于處理1:n聚合的映射,我們將在Foreign Key Aggregation的相關(guān)章節(jié)中討論它。
模式:Single Table Aggregation
摘要:
該模式展示了如何通過(guò)把所有的聚合的對(duì)象屬性集成到單個(gè)的表中的方法把聚合映射到一個(gè)關(guān)系數(shù)據(jù)模型。
示例:
考慮下列的對(duì)象模型:
圖1.一個(gè)AddressType,為其它的對(duì)象所聚合。
問(wèn)題:
如何將聚合映射到關(guān)系表中?
約束:
- 性能:為了得到最佳的性能,該方案應(yīng)該在一次的數(shù)據(jù)庫(kù)訪問(wèn)中,不用Join操作獲取一個(gè)對(duì)象。數(shù)據(jù)庫(kù)訪問(wèn)應(yīng)該只獲取最少的頁(yè)面,以節(jié)省IO帶寬。
- 可維護(hù)性:為了獲得最佳的可維護(hù)性,那些為多個(gè)對(duì)象所聚合的聚合類型,應(yīng)該映射到一組表中,而不是分散到物理數(shù)據(jù)模型的各個(gè)點(diǎn)上。在數(shù)據(jù)模型層次上實(shí)行標(biāo)準(zhǔn)化,這樣可以使維護(hù)簡(jiǎn)單。
- 數(shù)據(jù)庫(kù)的一致性:聚合意味著被聚合對(duì)象的生命周期和需要聚合的對(duì)象的生命周期是相互耦合的。這一點(diǎn)需要由數(shù)據(jù)庫(kù)或應(yīng)用程序代碼來(lái)保證。
解決方案:
把被聚合對(duì)象的屬性和使用聚合對(duì)象的屬性放在同一張表中。
結(jié)構(gòu):
使用聚合的對(duì)象被轉(zhuǎn)換為物理數(shù)據(jù)模型的一張表中,被聚合對(duì)象的數(shù)據(jù)集成到該表中。
解決方法示例:
我們?yōu)镃ustomer對(duì)象創(chuàng)建Customer表。InvoiceAddress和DeliveryAddress都集成到Customer表中。
圖2.將一個(gè)被聚合的對(duì)象類型映射到使用聚合的對(duì)象的數(shù)據(jù)庫(kù)表中。
我們使用前綴來(lái)區(qū)分同類的屬性。這有點(diǎn)類似于C++中的命名空間的概念,例如Customer.DeliveryAddress.Street。
結(jié)論:
- 性能:在性能方面,該方案是最佳的,因?yàn)橹恍枰L問(wèn)一張表就能夠獲取一個(gè)帶聚合的對(duì)象,并讀入所有聚合對(duì)象。另一方面,由于聚合對(duì)象的字段的增多,一次讀取將會(huì)增大數(shù)據(jù)庫(kù)讀入的頁(yè)面數(shù),導(dǎo)致IO帶寬的浪費(fèi)。
- 可維護(hù)性和靈活性:如果聚合的對(duì)象類型被多個(gè)對(duì)象所引用,那么將會(huì)降低可維護(hù)性,因?yàn)槊恳淮螌?duì)聚合對(duì)象類型的修改都會(huì)導(dǎo)致對(duì)所有引用聚合對(duì)象的修改。
- 數(shù)據(jù)庫(kù)的一致性:刪除使用聚合的對(duì)象時(shí),聚合對(duì)象將會(huì)自動(dòng)刪除。不需要任何其它的程序或數(shù)據(jù)庫(kù)觸發(fā)器來(lái)控制。
- 特殊查詢:類似查詢數(shù)據(jù)庫(kù)中所有的AddressType對(duì)象之類的查詢,都會(huì)變得很難處理。
實(shí)現(xiàn):
- 命名規(guī)則:需要為聚合的對(duì)象的屬性考慮前綴或其它的命名規(guī)則。在上面的例子中,我們使用屬性名稱的縮寫形式作為前綴。
- 物理數(shù)據(jù)庫(kù)的頁(yè)面大小:將聚合對(duì)象和使用聚合對(duì)象放在同一張表中,在一定程度上彌補(bǔ)了由于對(duì)象的部分屬性存儲(chǔ)在另一個(gè)數(shù)據(jù)庫(kù)頁(yè)面上的性能損失。這種情況下,讀入的是兩個(gè)頁(yè)面,而不是一個(gè)。
變化:
我們已經(jīng)討論了使用聚合對(duì)象類型和聚合對(duì)象類型之間最簡(jiǎn)單的1:1關(guān)系。Foreign Key Association模式描述了兩種對(duì)象類型間1:n的關(guān)系,Overflow Table則展示了在1:n的關(guān)系下避免采用外鍵的技巧。
相關(guān)模式:
Foreign Key Aggregation模式是Single Table Aggregation模式的備選方案。參考Representing Collections in a Relational Database [Bro+96]。當(dāng)應(yīng)用到普通的關(guān)系型數(shù)據(jù)庫(kù)訪問(wèn)層的時(shí)候,還可以對(duì)比Denormalization [Kel+97]。
參考:
《Mainstream Objects》(Ed Yourdon [You+95] )在第21章完整的討論了在建模時(shí)期何時(shí)使用聚合和關(guān)聯(lián)、以及如何使用它們的問(wèn)題。
模式:Foreign Key Aggregation
摘要:
該模式顯示了如何使用外鍵將聚合映射到一個(gè)關(guān)系數(shù)據(jù)模型中。
環(huán)境:
重新考慮Single Table Aggregation模式中的例子(見(jiàn)圖1)。假設(shè)你需要把AddressType視為單個(gè)的對(duì)象,并希望獲得比Single Table Aggregation更好的可維護(hù)性。
問(wèn)題:
如何將聚合映射到關(guān)系表?
約束:
見(jiàn)Single Table Aggregation模式。
解決方案
為聚合類型使用單獨(dú)的表。在表中插入Synthetic Object Identity,并使用使用聚合對(duì)象表中的對(duì)象標(biāo)記做一個(gè)外鍵,連接到聚合對(duì)象。
結(jié)構(gòu):
AggregatingObject(使用聚合對(duì)象)映射到一張表,而AggregatedObject(聚合對(duì)象)映射到另一張表。聚合對(duì)象的表中包含了Synthetic Object Identity。SyntheticOID字段被使用聚合表中的AggregatedObjectsOID外鍵字段引用。
解決方案示例
我們使用Single Table Aggregation模式中的例子。Customer表中包含了兩個(gè)外鍵引用,指向AddressType表。AddressType表包含了Synthetic Object Identity字段,用于連接兩張表。
現(xiàn)在從數(shù)據(jù)庫(kù)中獲取一個(gè)客戶對(duì)象需要三次訪問(wèn)數(shù)據(jù)庫(kù)(一次是對(duì)Customer表,另兩次是對(duì)AddressType:InvoiceAddress和DeliveryAddress),這要比Single Table Aggregation中多兩次。
如果AddressType表中增加指回Customer表中Synthetic Object Identity字段的回指字段的話,你就可以用連接來(lái)減少訪問(wèn)次數(shù)。這樣做的代價(jià)是在取客戶屬性時(shí)同時(shí)取回兩個(gè)地址。
結(jié)論:
- 性能:Foreign Key Aggregation需要連接操作或至少兩次的數(shù)據(jù)庫(kù)訪問(wèn),而Single Table Aggregation只需要一次的數(shù)據(jù)庫(kù)操作。如果訪問(wèn)聚合對(duì)象的概率較小,這個(gè)性能還是可以接受的,如果聚合對(duì)象總是需要和使用聚合對(duì)象一同返回,那么就需要慎重的思考性能問(wèn)題了。
- 可維護(hù)性:將對(duì)象做分解,例如單獨(dú)存放AddressType,這將使得維護(hù)更加容易,并提高映射的靈活性。
- 數(shù)據(jù)庫(kù)的一致性:聚合對(duì)象不會(huì)隨著使用聚合對(duì)象的刪除而自動(dòng)刪除。為做到這一點(diǎn),需要編程或使用數(shù)據(jù)庫(kù)觸發(fā)器來(lái)實(shí)現(xiàn)。
- 特殊查詢:將聚合對(duì)象放到單獨(dú)的表中可以簡(jiǎn)化對(duì)這些對(duì)象的查詢。
實(shí)現(xiàn)
- 可以考慮使用領(lǐng)域邏輯中的關(guān)鍵字來(lái)代替Synthetic Object Identitie。使用領(lǐng)域關(guān)鍵字的缺點(diǎn)是它們無(wú)法指回owner對(duì)象。
- 考慮在聚合對(duì)象中插入一個(gè)指回使用聚合對(duì)象的連接。在地址這個(gè)例子中,就是在地址表中插入一個(gè)字段,來(lái)表明AddressType對(duì)象的所有者。這個(gè)所有者可能是一個(gè)員工、一個(gè)客戶,或是其它需要使用AddressType的對(duì)象。雙向的關(guān)聯(lián)在查詢、一致性檢查和其它方面提供了方便。為了得到聚合對(duì)象的所有者,你不需要再次搜索使用聚合對(duì)象的表。另一方面,返回連接的開(kāi)銷比較昂貴。
相關(guān)模式
其備選方案為Single Table Aggregation。Foreign Key Association模式的工作方式和該模式非常接近。見(jiàn)Representing Collections in a Relational Database [Bro+96]。