摘要
在面向对象建模期间(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]。