日期:2013-11-02  浏览次数:20546 次

  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显示了四个方法。



图表1:枚举的实现方法 

  2.3类

  正常情况下,我们把每个类映射为一个表,每个属性映射为一个列。你可能因一个已产生的标识符(基于存在的标识符)、隐藏的关联(第2.4节)和通用鉴别器(第2.5节)需求一些另外的列。

  2.4关联

  如今我们讨论关联的实现。我们曾经把我们的陈述分为建议的映射(我们正常使用的映射),可选的映射(我们偶尔使用的映射)和不鼓励的映射(我们遇到的应该避免的错误)。我们所有的例子都采用基于存在的标识。

  2.4.1 建议的映射

  多对多关联。用一个特别的表(图表2)来实现一个多对多关联。关联的主键是每个类的主键的合并。那些省略号(...)表示在模型里没有显示出来的属性。主键用黑体字体显示。

  一对多关联。把一个外键隐藏在“多”表(图表3)。角色名字成为外键属性名字的一部分。

  零或一对一关联。把外键隐藏在“零或一”表(图表4)。

  其它一对一关联。把外键隐藏在任一表里。



图表2:建议的实现:特殊的多对多关联表



图表3:建议的实现:隐藏的一对多关联



图表4:建议的实现:隐藏的零或一对一关联

  可选的映射 正常情况下我们使用建议的映射。但有些偶尔的情况,可选的映射更合适。

  特别的表。你也可以用特别的表(图表5)来实现一对多和一对一关联。特别的表给了你更统一的设计和更大的扩展性。无论如何,特别的关联表打碎了数据库,并添加了表的数量。此外,特别的关联表不能强迫一个更低的多重性限制为“一”。



图表5:可选的实现:特别的一对x关联表

  不鼓励的映射 我们曾经留意到有些开发者选择有缺陷的映射。我们要留意这些映射以便可以避免。 合并。不要合并多个类,不要把关联强制成为一个单独的表(图表6)。这样减少了表的数量,但会干扰第三范式。

  两次隐藏一对一关联。不要把一个一对一关联隐藏两次,每次隐藏在一个类里(图表7)。这是多余的,无助于功用。

  相反的属性。不要用相反的属性来实现多个关联角色(图表8)。相反的属性使编程复杂,降低了扩展性。 泛化 如今我们讨论泛化。我们这里只论述单个承继。 建议的映射 最简单的方法是只映射超类和每个子类为一个表。所有的表共享一个共同的主键。使用必须执行子类的划分,由于RDBMS支持。(关于后者的详尽的描述,请参阅第4节。)

  特别的表。映射超类和每个子类为一个表(图表9)。所有的表共享一个共同的主键。鉴别器指出每个子类记录的适当的超类表。



图表9:建议的实现:分开的超类和子类表

  可选的映射 泛化有几个可选的映射。 消弭。你可以优化除去那些除了主键外没有别的属性的类(图表10)。这样减少了表的数量,但提供更少的正轨实现。

  减少超类属性。你可以除去超类表并把超类属性复制到每个子类(图表11)。这样可以有描述每个对象为一个表的优势。无论如何,它将惹起数据库结构的冗余,你查找一个对象时可能需求搜索多个子类表。

  添加子类属性。作为第三个可选项,你可以除去子类表并存储所有的子类属性到超类表里(图表12)。这样用一个表描述每个对象,但干扰了第二范式。



图表10:可选的实现:消弭不必的子类表



图表11:可选的实现:减少超类属性  



图表12:可选的实现:添加子类属性 

  参考完整性 一旦你曾经建立了表,你就应该定义参考完整性动作来明确对象模型的意义。(不要使用SQL触发器来实现参考完整性!)如果你使用基于存在的标识,你将不需求传播更新的结果。我们建议以下对删除的参考完整性方针: 泛化。级联从泛化实现中产生的外键的删除。

  隐藏的关联,最小化多样性为零。正常地把外键设为空,但有时候你可能要禁止删除。

  隐藏的关联,最小化多样性为空。你可以级联一个删除的结果或者禁止该删除。

  关联表。正常地我们级联关联表里对记录的删除。可是,有时候我们禁止一个删除。

  我们曾经简要地论及参考完整性,由于它是个高级话题。参考有更多的解释z和例子。 索引 实现数据库结构的最后的一步是加入索引来调整数据库功用。正常地,你应该为每个主键和候选键定义一个独一的索引。(多数RDBMS作为SQL主键和候选键约束的副作用来建立独一的索引。)你也应该为每个被主键或候选键所约束的外键建立一个索引。

  我