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