主题

简介到页首

本指南描述了反向设计数据库并将生成的数据模型表映射为设计模型中的设计类所涉及的步骤。此流程可以由数据库设计人员用以将修改的开发植入数据库中(作为演进开发周期的一部分)。数据库设计人员将需要在项目的整个开发生命周期内管理反向设计流程。在许多情况下,反向设计流程是在项目生命周期早期执行的,然后数据设计的更改受到递增地管理,而不需要随后对数据库执行反向设计。

反向设计数据库和将生成的数据模型元素转换为设计模型元素的流程的主要步骤如下:

  • 创建一个实际数据模型,所包含的表代表数据库中永久数据的实际布局。可以使用随关系数据库管理系统(RDBMS)提供的工具或通过最时新的可视建模工具自动执行此步骤。
  • 将实际数据模型中的表转换为设计模型中的设计类。此步骤可以通过先使用自动化工具进行初始转换、然后进行手动调整来执行。
  • 定义设计模型中多类之间的关联。
  • 基于对相应数据模型元素执行的操作,定义设计模型中类的相应操作。
  • 将设计模型中的类按需要分组为子系统和包。

反向设计 RDBMS 数据库或 DDL 脚本以生成数据模型到页首

数据库或数据定义语言(DDL)脚本反向设计流程通常在数据模型的一个或多个系统定义包中生成一组模型元素(表、视图、存储过程等)。 根据数据库的复杂性,数据库设计人员可能需要将反向设计的模型元素划分为包含逻辑相关的表组的几个主题区域包。

将数据模型转换为设计模型 到页首

可以按以下过程从数据模型中的模型元素生成设计类。将数据库的结构复制到类模型中,这是比较简单的。下面列出的流程描述了将数据模型元素转换为设计模型元素的算法。

下表显示了设计模型元素和数据模型元素之间常规映射的摘要。

数据模型元素 

对应的设计模型元素 

 
属性

非标识关系

关联 

交叉表

 

关联类

多对多关联

限定关联

标识关系

组装关系 

基数

 

多重性

 
使用枚举的子句检查约束 <<ENUM>> 类
模式  

数据模型中有一些在设计模型中没有直接相关关系的模型元素。这些元素包括表空间和数据库本身,它们对数据库的实际存储特征建模并由组件表示。另一项是数据库视图,它们是“虚拟”表,并且在设计模型中没有任何意义。 最后,对表的主键和数据库触发函数的索引(用于优化数据库的操作)仅在数据库和数据模型环境中才有意义。

将表转换为类 到页首

对于要转换的每个表,创建一个类来代表该表。对于每一列,使用适当的数据类型创建该类的一个属性。尝试尽可能使将属性的数据类型与相关联的列的数据类型相匹配。

示例

请考虑下图中显示的、具有以下结构的数据库表 Customer

列名称 数据类型
Customer_ID 数字
Name 变量字符
Street 变量字符
City 变量字符
State/Province 字符(2)
Zip/Postal Code 变量字符
Country 变量字符

Customer 表的表定义

由此起,我们创建一个类 Customer,其结构在下图中显示:

Customer 类定义

初始 Customer

在这个初始 Customer 类中,Customer 表中的每一列都有一个属性。每个属性都是公开可见的,因为可能会查询源表中的任一列。

请注意,属性左侧列出的“+”图标表示该属性是“公开”的;缺省情况下,从 RDBMS 表推导出的所有属性都应是公开的,因为 RDBMS 一般允许无限制地查询任一列。

标识嵌入式类或隐式类 到页首

从直接的表-类映射中生成的类通常将包含可以分为单独类的属性,尤其是在属性出现在多个转换类中的情况下。这些“重复的属性”可能是因为性能而对表反向规范化所生成的、或者可能是因为数据模型过度简化而生成的。在这些情况下,将相应的类分为两个或更多类,以代表这些表的规范化视图。

示例

定义上述 Customer 类之后,我们可以定义一个包含所有地址信息的 Address 类(假设我们的系统中还有其它事物具有地址),则生成以下类:

随附文本中描述的图。

修订的 Customer 类以及抽取的 Address

这两个类之间所画的关联就是一个聚集,因为客户的地址可以视为客户的一部分

处理外键关系 到页首

对于表中的每个外键关系,在相关联的类之间创建一个关联,从类中除去映射到外键列的属性。如果该外键列初始情况下表示为一个属性,则从类中除去它。

示例

假设 Order 表的结构如下:

列名称  数据类型 
Number  数字
Customer_ID  变量字符

Order 表的结构

在上面列出的 Order 表中,Customer_ID 列是一个外键引用;此列包含与 Order 相关联的 Customer 的主键值。我们将在设计模型中表示这一情况,如下所示:

UML 图如下所述。

在设计模型中表现外键关系

外键表示为类 OrderItem 之间的关联。

处理多对多关系 到页首

RDBMS 数据模型使用连接表关联表来表现多对多关系。 这些表使多对多关系可以使用一个中间表来表示,该表包含可连接在一起的两个不同表的主键。需要连接表的原因是因为一个外键引用仅可包含对单个外键值的引用;当一个单行可能与另一表中的许多其它行相关时,就需要一个连接表来与它们相关联。

示例

考虑 Product 的情况,Product 可由多个 Supplier 中的任一个提供,并且任一 Supplier 都可提供任意数量的 ProductProductSupplier 表的结构定义如下:

Product 表
列名称 数据类型
Product_ID 数字
Name 变量字符
Description 变量字符
Price 数字
Supplier 表
列名称 数据类型
Supplier_ID 数字
Name 变量字符
Street 变量字符
City 变量字符
State/Province 字符(2)
Zip/Postal Code 变量字符
Country 变量字符

Product 和 Supplier 表定义

为了将这两个表链接在一起以找出特定供应商提供的产品,我们需要一个 Product-Supplier 表,它在下表中定义。

Product-Supplier 表
列名称 数据类型
Product_ID  数字
Supplier_ID  数字

Product-Supplier 表定义

连接表包含产品和供应商的主键,并将它们链接在一起。该表中的一行将表示一个特定供应商提供一项特定产品。所具有的 Supplier_ID 列与特定供应商标识匹配的所有行将提供该供应商提供的所有产品的列表。

在设计模型中,这种中间表是多余的,因为一个对象模型就可以直接表现多对多关联。SupplierProduct 类及其关系在下图中显示,还有 Address 类,后者是按照先前的讨论从 Supplier 中抽取的。

UML 图,在图表说明中描述。

Product 和 Supplier 类表现

简介泛化关系 到页首

通常,您将会发现具有某种类似结构的表。在数据模型中,没有泛化关系的概念,所以无法表现出两个以上的表具有某种共同的结构。有时公共结构源自因为性能而进行的反向规范化,例如在上述情况下我们将“隐式”的 Address 表抽取到一个单独类中。 在其它情况下,多个表共享更基础的特征,我们可以将这些特征抽取到一个具有两个以上子类的泛化父类中。要发现泛化的机会,则在几个表(这些表与其说不同,不如说相似)中查找重复的列。

示例

考虑以下的表 SoftwareProductHardwareProduct,如下所示:

Software Product 表
列名称  数据类型 
Product_ID  数字
Name  变量字符
Description  变量字符
Price  数字
Version  数字
Hardware Product 表
列名称  数据类型 
Product_ID  数字
Name  变量字符
Description  变量字符
Price  数字
Version  数字


SoftwareProduct 和 HardwareProduct 表

请注意,以蓝色突出显示的列是完全相同的;这两个表所共享的定义大体相同,仅略有差别。我们表现这一点的方式是抽取一个公共的 Product 类,并以 SoftwareProductHardwareProduct 作为 Product 的子类,如下图所示:

随附文本中描述的图。

SoftwareProduct 和 HardwareProduct 类,显示泛化为 Product 类

在下图中,所有类定义放在一起,显示了一个订单输入系统的合并类图(仅限于主要类)。

随附文本中描述的复杂 UML 图。

订单输入系统的合并类图

在设计模型中复制 RDBMS 行为 到页首

复制行为更困难,因为通常关系数据库不是面向对象的,并且似乎与对象模型中对类的操作没有任何相似之处。以下步骤可能有助于重新构建上述类的行为:

  1. 创建操作以获取和设置每个属性。需要设法设置、更改和查询对象的属性值。由于访问对象属性的唯一方式是通过类提供的操作,故必须对类定义此类操作。 创建设置属性值的操作时,务必合并可能对相关联的列起作用的任何验证约束。如果没有任何验证约束,则可选择只表现通过将属性标记为具有“公开”可见性来获取设置属性这一事实,如上述几个图中所示(图标在属性名称的左侧)。
  2. 为在相关联的表上操作的每个存储过程创建对该类的操作。存储过程是在 DBMS 自身内部执行的可执行子例程。这种逻辑需要转换到设计模型中。如果一个存储过程只对一个类起作用,则使用与该存储过程相同的参数和返回类型创建对该类的一个操作。记录该操作中存储过程的行为,确保在方法描述中记录该操作是由存储过程实施的。
  3. 创建操作以管理多类之间的关联。当两个类之间存在关联时,则必定可设法创建、管理和除去关联。对象之间的关联是通过对象引用来管理的,所以为了在 OrderLineItem 之间创建关联(即,将 LineItem 添加到 Order),将调用对 Order 的操作,将 LineItem 作为实参传递(即 Order.add(aLineItem))。必定还可设法除去和更新关联(即 Order.remove(aLineItem)Order.change(aLineItem,aNewLineItem))。
  4. 处理对象删除操作。如果目标语言支持显式删除,则向类的析构函数添加行为,实施参照完整性检查。在数据库中有参照完整性约束的情况下(例如级联删除),则需要在相应的类中复制该行为。例如,该数据库可能定义如下约束,即只要删除一个 Order,所有相关联的 LineItems 均应被删除。如果目标语言支持垃圾回收,则创建如下机制,即当将相关联的对象作为垃圾回收时,可以从表中除去多行。请注意,这做起来比听起来难(听起来也很困难),因为您将需要实施一种机制,确保没有任何数据库客户机对要作为垃圾回收的对象有任何引用;依靠执行环境/虚拟机的垃圾回收能力是不够的,因为这毕竟只是一个客户对现实的了解。
  5. 处理查询所暗示的行为。检查访问表的 Select 语句,以了解如何检索和操纵信息。对于 Select 语句直接返回的每一列,将相关联属性的 public 特征均设置为 true;所有其它属性均应为 private。对于 Select 语句中每个计算的列,创建对相关联的类的操作,以计算和返回该值。考虑 Select 语句时,还要包括“视图”定义中嵌入的 Select 语句。

在设计模型中组织元素 到页首

在设计模型中,根据表-类转换而创建的设计类应,(在需要时)基于应用程序的整体体系结构结构,组织为相应的设计包和/或设计子系统。关于应用程序体系结构的概述信息,请参阅概念:分层概念:软件体系结构



Rational Unified Process   2003.06.15