第二章                      数据库建模

 

本章要点

1、掌握数据库建模的两种基本方法:

对象定义语言(ODL)和实体-联系模型(E/R图)

2、会用这两种方法建立简单的数据库模型。

3、了解数据库设计的基本原则

4、掌握用ODL和E/R图表示子类的方法

5、了解子类的继承性

6、深入理解键码和引用完整性这两个基本概念

 

 

数据库建模概述

1、数据库的结构,也称为数据库模式。因此,确定数据库的结构的过程就称为数据库建模。

 

2、两种主要数据库模式表示法:

实体联系模型,也叫做E/R图 ,矩形表示实体, 椭圆形表示属性,菱形和箭头表示联系。

        对象定义语言(ODL):是面向对象的数据库设计方法

 

3、数据库设计的过程图

 

 

 

 

 

 

 

 

 

 


4、面向对象的设计

       所谓对象,就是某种可观察、可研究的实体;一个人、一门课程、一本书等等都可以作为对象。

            每个对象都有唯一的标识,使其能区分于任何其他的对象。

            可把具有相似特性的对象归为一类。

 

 

 

 

2.1       对象定义语言ODL

    ODL主要用于书写面向对象数据库的设计,进而将其直接转换成面向对象数据库管理系统(OODBMS)的说明。

OODBMS的基本语言一般是C++或者Smalltalk,所以必须把ODL转换成其中一种语言的说明。

ODL与C++非常类似,这种转换相当方便。

 

2.1.1   面向对象的设计

ODL类的三种特性:

1、属性(Attribute),它们的类型由基本的数据类型构成。

2、联系(Relationship),它们的类型是对某类对象的引用或引用的集合。

3、方法(Method),是能用于该类对象的函数。

 

2.1.2    类的说明

关键字interface(接口)

类名

类的特性表(属性、联系和方法)

               interface     <类名>   {

                                    <特性表>

                            }

2.1.3  ODL中的属性

属性用来描述对象的某个方面。

例:学生选课数据库中,每门课中有三个属性:CourseNo(课程号)、CourseName(课程名)、Teacher(老师),可用ODL表示如下:

interface  Course {

                        attribute integer CourseNo;

                         attribute string CourseName;

                        attribute string Teacher;

         }

我们再定义一个简单的学生类:

interface Student {

                       attribute integer StudentNo;

attribute string StudentName;

attribute integer Age;

attribute string Dept;

}

 

2.1.4  ODL中的联系和反向联系

描述一个对象与其他对象之间的联系。例: 

课程和学生之间存在选课联系,在课程类的说明中增加一个学生集合,作为课程类和学生类之间的联系:

 

relationship  Set  <Student>  students; 

 

反向联系

relationship Set  <Student>  students

                                    inverse     Student::courses;

relationship Set  <Course>  courses

inverse     Course::students;

 

       一个较完整的课程类定义:

interface Course  {

attribute integer CourseNo;

attribute string CourseName;

attribute string Teacher;

relationship Set <Student> students

inverse    Student::courses;

}

2.1.5         联系的类型

          一对一 、一对多、多对一和多对多

 

2.2   实体联系模型(E/R图)

 

一、用图形表示的数据库建模方法——E/R图

实体集:实体是实体集的成员,和ODL中的对象相似。矩形表示实体集。

   属性: 与ODL中的属性本质上相同。椭圆形表示属性。

   联系: 与ODL中的联系本质上也相同,E/R图中的联系可以涉及两个以上的实体集。菱形表示联系。

 

2.2.1  E/R图中联系的三种类型

    用箭头的有无来区别三种不同的联系。

1、从实体集A到实体集B的多对一联系,画一个指向B的箭头。

2、从实体集A到实体集B的一对一联系,画两个箭头,分别指向A和B。

3、若为多对多联系,则两边均无箭头。

 

2.2.2 联系中的角色

在一个联系中,一个实体集可能出现两次或多次;倘若如此,一个实体集在联系中出现多少次,我们就从该联系到该实体集画多少条线。到实体集的每一条线代表该实体集所扮演的每一个角色,我们把它扮演的角色标记在连线的侧面

例:一门课可能有几门先修课,比如“C++程序设计数据结构等就是数据库原理的先修课;而同一门课也可能是几门其他课的先修课,比如“C++程序设计既是数据结构也是数据库原理的先修课。因此实体集Course和它本身的联系prelearn(先修)是多对多的。

                其对应的E-R图如下:

                             predecessor

 

 

 

 

 


                        successor

 

 

2.2.3  联系的多向性

 

 

 

联系有时不仅局限于两个实体集之间,也可能涉及到三个或更多的实体集,这时就构成了多向联系。

例如:学生选课关系中,增加一个实体集Teacher(老师),把Course的属性Teacher换成与实体集Teacher的联系;这样,学生选课联系就涉及到三个实体集:Student,Course,Teacher。如下图示:

 

 

 

 

 

 

 

 


假设一门课可有几位老师开设,而每位老师都可开设几门课,学生可在选课的同时选择老师。

指向Teacher的箭头表示对于特定的学生和课程,只有一位老师与它们相对应。

没有指向实体集Student和Course的箭头意味着,一个学生可以选修一个老师开的几门课,而一个老师开的一门课也可以有多个学生去选。

在多向联系中,指向某个实体集E的箭头意味着,如果从与该联系相连的其他几个实体集中各取出一个实体,那么这几个实体将与E中唯一的实体相关。

虽然用多向(多元)联系能更形象地反映某些现实世界,但从数据库建模的角度,用二元联系更为方便。

 

 

 

 

 

 

 


可将多元关系转换成二无关系,见如下图示:

 

 

 

 

 

 

 

2.3设计原则

真实性 、避免冗余、简单性和合理选择元素类型

 

2.3.1  真实性

最基本的设计原则:类(实体集)和属性应当是真实的,应当反映客观现实。

在设计时,首先要对客观世界进行准确、全面的分析,然后在此基础上进行正确、合理的抽象。

 

2.3.2        避免冗余

在设计过程中还要注意,任何事物都只表达一次,否则既浪费空间,又容易造成不必要的麻烦。

 

2.3.3  简单性

在设计数据库的过程中,一定要设法避免引入过多的元素,而应该尽量简单明了。

 

2.3.4  合理选择元素类型

究竟是把某种元素作为属性,还是单独作为一个类或实体集?

属性比类/实体集或者联系实现起来简单一些。

 

 

2.4 子类

把类中的某些对象组织成子类,除了作为整体的类的特性以外,每个子类有它自己的附加属性和/或联系。

 

 

2.4.1  ODL中的子类

期定义子类的方法:

在类名A之后加上冒号和另一个类B的名字,就可以定义类A是类B的子类。

例如:学生类的研究生类表示

interface PostgraduateStudent  {

       attribute string Tutor//导师姓名

}

子类能自动继承其超类(就是子类从中派生的类)的所有特性。

上例中,每个研究生对象都有从Student中继承下来的属性StudentNo、StudentName、Age和Dept,并从Student中继承了联系Courses,除此之外,还有它自己的属性Tutor。

 

2.4.2  ODL中的多重继承

一个类可以有多个子类,而子类本身又可以具有子类,形成类的层次结构。

另外,一个类还可能有多个超类。 例如:

《谁陷害了兔子罗杰》既是动画片,又是谋杀片。除了具有普通电影的四个属性和两个联系之外,还应该有联系voices和属性Weapon。可以定义另外一个子类Cartoon_Murder(动画-谋杀片),它是Cartoon(动画片)和Murder(谋杀片)两者的子类:

描述如下:

     interface Cartoon_Murder:

Cartoon,Murder {  } ;

ODL的实现至少提供如下机制之一来保证用户能够避免由于多重继承而产生的冲突:

1. 指出特性(属性或者联系)的两个定义中哪一个适用于子类。

2. 重新命名有相同名字的另一个特性。

3. 为子类重新定义在它的一个或多个超类中已经定义过的某些特性。

 

2.4.3 E/R图中的子类

   假定类A是类B的子类,为了表示出A和B之间的关系,我们用一种称作属于“isa”)的特殊联系将实体集A和B相连。

“isa”联系用一个三角形和两条连向实体集的线来表示,三角形的尖端指向超类,三角形中还要写上“isa”的字样。见如下图例:

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


2.4.4  E/R图中的继承

E/R模型与ODL或者其他面向对象的模型在继承这个概念上有一些细微的差别。

ODL中,对象必须恰好是一个类的成员,而在E/R图中,我们不需要这样的实体集。

 

 

2.5  对约束的建模

现实世界中有很多重要的方面对数据具有一定的约束。

常见的约束信息可以分为如下几类:

1.键码(key)

2.单值约束

3.引用完整性约束

4.域约束

5.一般约束

 

2.5.1键码 (key)

 

 

在类的范围内唯一标识一个对象(在ODL中),或者在实体集的范围内唯一标识一个实体(在E/R图中)的属性或属性集。一个类中的任何两个对象在构成键码的属性集上的取值决不能相同,否则键码就名不副实,不能唯一标识一个对象。

例如:在电影资料数据库中,可能有同名的电影,因此就把两个属性Title和Year的集合作为键码。

实际上,情况并不总像上例那么复杂,我们往往在设计数据库的时候为重要的类特别建立有效的键码,例如学校为所有学生分配唯一的学号,公司为所有职员分配唯一的员工号等等,这样就可以很方便的区分数据库中的对象或实体。

在有的情况下,一个类或实体集可以有几个键码。假设制片公司有公司注册号这个属性的话,那么公司注册号也可以和公司名一样作为类Studio的键码,因为公司注册号是不会重复的。

ODL中,可以用关键字key或者keys(这两者效果相同)来说明一个或多个属性为一个类的键码,构成键码的属性要跟在关键字后面。

如果键码由多个属性组成,则这种键码称为复合键码,且属性表必须用圆括号括起来。键码说明必须紧跟在接口说明的后面,它本身也要用圆括号括起来。

例如:两个属性Title和Year的集合构成键码

            interface Movie

                (key(Title, Year)){

                    }

            两个属性Name和StudioNo都为键码

              interface Studio

              (key Name, StudioNo){

}

E/R图中,同样可以用很简单的手段来表示键码。假如实体集的某个属性在键码的属性集中,就在该属性下面划一条横线。

在有多个键码的情况下,E/R图不提供正式的表示法来表示所有的键码。通常我们会选择一个键码作为主键码,并把它看作是实体集唯一的键码,用下划线来标明。至于其他的键码,称为次键码或候选键码,一般不在E/R图上标出,或者在图的旁边作出注释。

 

                      2.5.2  单 值 约 束

要求某个属性的值是唯一的,键码是单值约束的主要来源。由于键码能唯一地标识一个元组(或一个对象,一个实体),因此,当键码值给定时,该元组(或对象,实体)的其他属性值也都唯一地确定了。明确键码是单值约束的来源,会给数据库的管理带来很大方便。

通常在进行数据库设计的时候,会要求对象的某个属性只有唯一的值。

例如,我们假定每个学生对象有唯一的学号、姓名,每部电影有唯一的名称、年份、长度,并且每部电影只属于唯一的制片公司等等。

ODL可以很容易的说明这些假定,因为每个属性或联系都有一个类型,假如该类型不是一个聚集类型(比如说集合),那么对于该属性就只有一个值,或者对于一个联系只有一个相关的对象。

假如把属性或联系定义为聚集类型,例如电影类Movie中对演员类Actor的联系actors的类型为Set<Actor>,那么就允许一部给定的电影和多位演员相关,这种联系称为多值联系。

 

我们还需要区别一个属性或联系最多有一个值的情况(即我们正在讨论的单值约束)和必须有一个值(即不能为空)的情况。

当我们对一个属性进行单值约束的时候,有两种选择,一是要求该属性值存在,二是允许该属性值任选。如果类的一个属性是键码的一部分,那么我们一般要求类中每个对象的该属性值都存在;如果该属性不是键码的一部分,通常允许该属性值不存在,这时,我们可以对该属性建立null值(值)来表示允许该属性的值任选。

E/R图也提供了表示单值约束的方法。实体集的每个属性都隐含地具有单一的值。通常我们还假定,属性的值可能为空,不能为空的属性将在边上标明。表明多对一或一对一联系的箭头也表示单值约束。如果实体集A的一个联系有指向实体集B的箭头,那么实体集B中最多有一个实体与实体集A中的某个实体相连。

 

2.5.3  引用完整性约束

要求某个对象所引用的值在数据库中确实存在。

完整性一般体现在两方面:

     对属性,要求其有非空的单值;

     对联系,要求所引用对象存在且唯一。

一个实体的键码属性值不能为空,称为实体完整性;

一个实体的某个属性(集)值只能引用另一实体确实存在的键码属性(集)值,则称为引用完整性。

比如,在学生选课数据库中,若要删除某个学生对象,则除了删除该学生的学号及其相关的属性值以外,还应同时删除与该学号对应的所有选课courses(所选课程集合),并从所有相关课程的联系students(选课学生集合)中删除该学号。

Student(StudentNo,StudentName,Dept)

Course(CourseNo,CourseName,Teacher)

SC(StudentNo,CourseNo,Grade)

主键码:

StudentNo

CourseNo

StudentNO,CourseNo

外键码

StudentNO     CourseNo

 

要在E/R图中表示对引用完整性的约束也比较简单。假定R是一个从实体集A到实体集B的联系,如果指向B的是一个圆箭头,则不仅表明R是从A到B的多对一或一对一联系,而且对于实体集A的一个给定的实体,要求存在一个与之相关的实体集B的实体。

 

2.5.4  域 约 束

要求某个属性的值必须处于特定的范围内或者取自特性值的集合。

例如,学生的学号StudentNo是整数类型,因此学号的取值只能在整数范围内。

又如,学生选课的课程号必须是课程号的集合中的一个元素,而不能是集合外的某一数值。

 

把属性的值限制在一个有限的集合之内。

ODL在说明一个属性时要求带上属性的类型,这个类型就是域约束最基本最初级的形式。

比如,电影长度的类型是整数,那么长度的值就不能是92.5或者其他的非整数。然而,ODL不支持更进一步的限制性约束,例如要求长度在30到180之间。

还有更多普通类型的约束不属于本节所提到的任何一个范畴。

例如,我们规定一个电影对象或实体不能通过联系Act与8个以上的演员对象或实体相连;在E/R图中,我们可以在联系和实体集的连线旁边标出这个数量限制;在ODL中,我们可以让Movie的联系actors是长度为8的数组类型,从而限制演员的数量,因为我们没办法限制一个集合最多有8个元素。

 

2.5.5  一般约束

有些时候,我们希望在数据库中实施一些其他类型的约束。    

在这里我们先对其他的约束作一简要的说明,本书以后的章节会详细阐述这个问题。

 

                      本章小结

数据库建模(Database Modeling)

            对象定义语言   ( ODL ,Object       Definition                    Language)

            实体/联系模型(Entity/Relationship Model)

            联系的三种类型

 设计原则

            子类(Subclass)

            对约束建模(Modeling of       Constraint)

            键码(Key)

            引用完整性(Reference          Integrity)