1. 介绍 许多人认为面向对象概念和关系型数据库相互不一致,并且不能结合。事实上完全相反!经过灵活的使用,一个关系型数据库能够为面向对象(OO)模型提供一套优秀的实现。同样的模型能够用来开发编程代码和关系型数据库结构。 关系型数据库技术是意义深远
1. 介绍
许多人认为面向对象概念和关系型数据库相互不一致,并且不能结合。事实上完全相反!经过灵活的使用,一个关系型数据库能够为面向对象(OO)模型提供一套优秀的实现。同样的模型能够用来开发编程代码和关系型数据库结构。
关系型数据库技术是意义深远的、强大的,但它比许多开发商使你相信的要难得多。单个表是简单易懂的、直观的。但由数以百计的表组成(这是常见的)的应用要彻底了解是相当困难的。这正是OO模型有用之处。 OO模型使你深入地、连贯地思考问题。
OO模型提供一种问题的超结构(superstructure)的思考方式,然后该方式能够用关系型数据库的更低层的组成块来实现。
本文章综合地讨论了关系型数据库技术,而不是集中于特定的产品上。我们将不讨论物理设计细节(例如存储分配和物理聚集),因为它们是依赖于产品的。
用关系型数据库实现UML模型有两个方面:映射结构(第2节)和映射功能(第3节)。第4节注解了面向对象到关系型数据库的扩展。第5节总结本文章。
2. 结构映射到表
UML对象模型在本质上只是一个扩展的实体-关系(ER)模型
。使用设计数据库的ER模型的方式受到普遍接受,而我们以一种近似的但更强大的方式-使用UML对象模型。OO模型的主要优势在于编程和数据库的相同的模
型工作。而且,作为考虑功能性的一种方式(第3节),我们强调OO模型的导航。这一节显示如何实现UML对象模型的主要构造。
2.1 标识(identity)
实现对象模型的第一步是处理标识。我们从定义几个术语开始。
1)候选键(candidate key)是一个或多个属性的组合,它唯一地确定某个表里的记录。一个候选键里的属性集必须是最小化的;除非破坏唯一性,否则属性不能从候选键删除。候选键里的属性不能为空。
2)主键(primary key)是一个特定地选定的候选键,用来优先地参考记录。
3)外键(foreign key)是一个候选键的参考。外键必须包括每个要素属性的一个值,或者它必须全部为空。外键用来实现关联和一般化。
正常地你应该为每个表定义一个主键,尽管偶尔有例外。我们强烈建议所有的外键都只指向主键而不是其它的候选键。
定义主键有两种基本的方法:
1)基于存在的标识。你应该为每个类表加一个对象标识符属性,并将它设为主键。每个关联表的主键包括一个或更多的相关类的标识符。基
于存在的标识符有作为单独属性的优势,占位小且大小相同。只要你的关系型数据库管理系统(RDBMS)受支持,基于存在的标识符就没有性能的劣势。(多数
RDBMS提供有效的基于存在的标识符的分配顺序号码。)唯一的劣势是基于存在的标识符在维护时内没有固有的意义。
2)基于值的标识。一些真实世界的属性的组合确定了每个对象。基于值的标识有不同的优势。主键对于用户有固有的意义,容易进行调试和数据库维护。在另一面,基于值的主键很难改变。一个主键的改变需要传播到许多外键。一些对象没有自然的真实世界里的标识符。
我们推荐你在超过30个类的RDBMS应用里使用基于存在的标识。基于存在和基于值的标识都是所有RDBMS应用的可行选项。
2.2 域(属性类型)
属性类型是UML术语,对应于数据库著作里的域的术语。比起直接用数据类型,域提升到更一致的设计,并便利了应用的定位。
简单域很容易实现。你仅仅要定义相应的数据类型和大小。并且每个用了域的属性,你都必须为每个域约束加入一条SQL查询子句。简单域的一些例子是:名字(name),长字符(longString)和电话号码(phone-Number)。
一个枚举域把一个属性限制在一系列的值里。枚举域比简单域实现起来更复杂,图表1显示了四个方法。
2.3类
正常情况下,我们把每个类映射为一个表,每个属性映射为一个列。你可能因一个已产生的标识符(基于存在的标识符)、隐藏的关联(第2.4节)和通用鉴别器(第2.5节)需要一些另外的列。
2.4关联
现在我们讨论关联的实现。我们已经把我们的陈述分为建议的映射(我们正常使用的映射),可选的映射(我们偶尔使用的映射)和不鼓励的映射(我们遇到的应该避免的错误)。我们所有的例子都采用基于存在的标识。
2.4.1 建议的映射
多对多关联。用一个特别的表(图表2)来实现一个多对多关联。关联的主键是每个类的主键的合并。那些省略号(...)表示在模型里没有显示出来的属性。主键用黑体字体显示。
一对多关联。把一个外键隐藏在“多”表(图表3)。角色名字成为外键属性名字的一部分。
零或一对一关联。把外键隐藏在“零或一”表(图表4)。
其它一对一关联。把外键隐藏在任一表里。
可选的映射 正常情况下我们使用建议的映射。但有些偶尔的情况,可选的映射更合适。
特别的表。你也可以用特别的表(图表5)来实现一对多和一对一关联。特别的表给了你更统一的设计和更大的扩展性。无论如何,特别的关联表打碎了数据库,并增加了表的数量。此外,特别的关联表不能强迫一个更低的多重性限度为“一”。
不鼓励的映射 我们已经注意到有些开发者选择有缺陷的映射。我们要注意这些映射以便可以避免。 合并。不要合并多个类,不要把关联强制成为一个单独的表(图表6)。这样减少了表的数量,但会干扰第三范式。
两次隐藏一对一关联。不要把一个一对一关联隐藏两次,每次隐藏在一个类里(图表7)。这是多余的,无助于性能。
相同的属性。不要用相同的属性来实现多个关联角色(图表8)。相同的属性使编程复杂,降低了扩展性。 泛化
现在我们讨论泛化。我们这里只论述单个继承。 建议的映射
最简单的方法是只映射超类和每个子类为一个表。所有的表共享一个共同的主键。应用必须执行子类的划分,因为RDBMS支持。(关于后者的详尽的描述,请参
阅第4节。)
特别的表。映射超类和每个子类为一个表(图表9)。所有的表共享一个共同的主键。鉴别器指出每个子类记录的适当的超类表。
可选的映射 泛化有几个可选的映射。 消除。你可以优化除去那些除了主键外没有别的属性的类(图表10)。这样减少了表的数量,但提供更少的正规实现。
减少超类属性。你可以除去超类表并把超类属性复制到每个子类(图表11)。这样可以有描述每个对象为一个表的优势。无论如何,它将引起数据库结构的冗余,你查找一个对象时可能需要搜索多个子类表。
增加子类属性。作为第三个可选项,你可以除去子类表并存储所有的子类属性到超类表里(图表12)。这样用一个表描述每个对象,但干扰了第二范式。
参考完整性
一旦你已经建立了表,你就应该定义参考完整性动作来明确对象模型的意义。(不要使用SQL触发器来实现参考完整性!)如果你使用基于存在的标识,你将不需
要传播更新的结果。我们建议以下对删除的参考完整性方针: 泛化。级联从泛化实现中产生的外键的删除。
隐藏的关联,最小化多样性为零。正常地把外键设为空,但有时候你可能要禁止删除。
隐藏的关联,最小化多样性为空。你可以级联一个删除的结果或者禁止该删除。
关联表。正常地我们级联关联表里对记录的删除。可是,有时候我们禁止一个删除。
我们已经简要地论及参考完整性,因为它是个高级话题。参考有更多的解释z和例子。 索引
实现数据库结构的最后的一步是加入索引来调整数据库性能。正常地,你应该为每个主键和候选键定义一个唯一的索引。(多数RDBMS作为SQL主键和候选键
约束的副作用来建立唯一的索引。)你也应该为每个被主键或候选键所约束的外键建立一个索引。
我们强调索引的重要性。外键和主键的索引使在对象模型里能快速地遍历是不容怀疑的。你必须包括这些索引否则你将使用户感到灰心。你应该在你的数据库开始设计阶段里加入索引,因为它们很容易加入并且也没有什么好理由推迟加入。
数据库管理员(DBA)可能为经常请求的查询定义了额外的索引。DBA也可能采用产品相关的调整性能的机制。 范式
范式是关系型数据库设计的提高数据一致性的有效方法。我们的书3讨论了范式,但我们关于这个问题却言过甚微。我们将利用这篇文章的机会来澄清我们的观点。
如果你不熟悉范式你可以跳过这节。我们的说明是针对关系型设计人员,他们正在尝试用面向对象适应他们原有的技能。
范式是正确设计关系型数据库的精确的原则。同样地,它们与使用了什么开发技术是无关的 -
基于属性的设计、基于实体的设计、面向对象设计或其它什么。
过去使用基于属性设计的方法,开发人员不得不非常注意范式;范式提供了分组数据的根据。相反地,范式对于基于面向对象(或基于实体)的开发不是很重要。如
果你采用OO方法并且你的模型经过很好的构思,那你就正在把数据组织成为有意义的单位,也在本质上满足了范式的规定。如果你愿意,你仍能够检查范式,但这
样的检查是不必要的。 摘要
图表13总结了我们已经陈述的映射规则。这些映射规则的完整例子,包括一个UML对象模型,能够在这篇完整的扩展版本里找到(Adobe Acrobat
PDF文件)。
把功能映射到SQL命令 对象模型为数据库应用提供三种主要的用途。 结构。对象模型指明数据库结构。我们已经在第二节探讨了这个方面。
约束。对象模型也指明了能存储的数据上的重要的约束。相匹配的实现必须为迎合这些约束而努力。我们的映射规则的处理方法以及第二节里的参考完整性指出了许多约束。(本文没有论及的另外的UML构造,能获取更多的约束。)
潜在估算。一个对象模型指明潜在估算;它是关于引起哪些查询和如何公式化的蓝图。第三节将简要地阐明第三个目的。
对象模型不仅仅是被动的数据结构,相反它们能够帮助你思考一个应用的功能。你可以根据遍历一个对象模型说出它的许多功能。例如,根据
我们对一个模型检查用例时的遍历,我们进行思索。这强调对象模型的估算能力对于RDBMS应用是特别重要的,因为遍历表达式可以直接映射到SQL代码。
UML对象约束语言(Object Constraint
Language,OCL)有助于表达遍历。点符号导航从对象到对象和对象到属性。方括号表示对象集合的过滤器。我们加入冒号(:)操作符来表示泛化的遍
历;因为我们正常地用多个表来实现一个泛化继承,清楚的遍历很有用。
图表14里的遍历表达式例子是基于我们创建的UML对象模型上的(请参阅本文的扩展版本(Adobe Acrobat PDF文件)),我们把它们映射为SQL代码。我们用冒号开始SQL编程变量。
到RDBMS的OO扩展
数据库团体对RDBMS的OO扩展有兴趣。产品和SQL标准正尝试加入到OO扩展里。我们将简要地陈述一下这个技术的方向。
抽象数据类型(ADT)。这是个好主意,扩展RDBMS的能力。开发商为这个技术使用了许多名字,例如Oracle
cartridge和Informix data
blades。ADT的缺点是它们把你紧紧绑在特定的一个开发商上;ADT的范畴超越了SQL标准。因此,你应该只在ADT的好处很明显的时候才使用。
在关于ADT如何适合数据库开发的著作里有一些混乱。如果你使用OMT开发过程,你能够用属性实现简单域,用ADT实现复杂域。你仍
应该用表实现类。
SQL3指针。最新的SQL标准的版本,SQL3,加入了作为一种数据类型的指针符号。显然,其意图是支持导航和面向对象。我们对于SQL3指针最友善的
评语是,它们是嫁接的,是可以忽略的。更深入的批评是,指针在理论上是荒谬的,增加了复杂性,又没有扩展SQL的表达能力。CJ
Date在上次的九月对象/关系型会议上雄辩地讨论了这一点。
好了,那么我们冷淡地对待抽象数据类型和SQL指针的指责。但我们相当喜欢面向对象技术和关系型数据库。有两个为RDBMS的扩展可
以使它们更容易用于OO技术。我们将很乐意看到RDBMS开发商把这些能力加入到他们的产品中。
扩展的参考完整性动作来支持泛化。当前的参考完整性机制是单向的。为了完全支持泛化,我们需要一个双向的机制。这样,一条超类记录就可以依赖一条子类记
录。并且,一条子类记录就可以依赖一条超类记录。我们通过例子可以最好地解释这点。
图表15摘录于我们的在3的财务案例学习。我们用资产超类来统一某些没有显示在摘录里的通用的数据和功能。一项资产可以是一只股票或股票特权。一只股票可以有许多它的股票特权。例如,IBM股票可以有许多达到价格和过期日期的写下的放或叫特权。
我们推荐的泛化实现是特别的表 -
映射该超类和每个子类为一个表。然后,我们就可以使用参考完整性使股票特权和股票的记录依赖于资产。一个资产记录的删除级联到相应的子类记录、股票特权或
股票的删除上。我们也能够定义一个参考完整性动作,这样一个股票的删除就级联到关联的股票特权记录的删除。
现在问题如下。如果我们删除的一项资产是一只股票,资产记录的删除级联到引起股票记录的删除。随后,股票记录的删除级联引起所有股票
特权记录的删除。但现在参考完整性使我们失败了:一个股票特权记录的删除并不引起一项资产记录的删除。删除级联只能从超类走到子类。为了完全的行为,级联
应该双向地走下去。
当前有用的参考完整性的工作是做更多的编程(也即做更多的工作和风险更多故障)。在我们的用例学习的实现里,用户随时要删除一项是股
票的资产,我们不得不书写额外的代码来首先检查关联股票特权的存在性,然后删除它们。
支持交叉表的记录划分。单独继承(泛化的最常见方式)的含义是一个超类的每个实例都是用多数只有一个子类来例示。现在的RDBMS不能容易地加强这个约
束。例如,没有什么防止下面的情形。一只股票可以用ID18加入到资产表,用ID18加入到股票表,并且也可以用ID18加入到股票特权表。再一次地,我
们为了确信行为的完整,不得不作额外的编程,而不是写一个简单的声明的约束
结论
本文陈述了用关系型数据库实现UML模型的快速的概观。我们希望本文向你演示的技术是足够适宜的。一个训练有素的开发人员能够用关系
型数据库准备一套优秀的OO模型的实现。如果你要关于实现机制的更多的细节,参考3有另外的信息,并且也覆盖了我们没有在这里讨论的一些高级模型建模结
构。
来源 http://tech.ccidnet.com/art/291/20030811/58724_1.html