下图所示的 ER 图是对 DreamHome 案例的 Branch 视图 ER 建模的结果。
1. 实体类型
实体类型:被企事业单位认可的、能够独立存在的一组具有相同属性的对象。
ER 模型的基本概念是 实体类型,实体类型代表现实世界中具有相同属性的一组对象。实体类型能够独立存在,既可以是物理(真实)存在的对象,也可以是概念(抽象)存在的对象,具体实例如下表所示。注意,关于实体类型我们只能给出一个能工作的定义,目前尚不存在一种严格的形式化定义。这意味着不同的设计人员可能会确定不同的实体。
实体出现(entity occurrence):实体类型中可唯一标识的一个对象。
一个实体类型中每一个可被唯一标示的对象都可简称为一个实体出现。本书使用 “实体类型” 或 “实体出现” 这两个术语,然而在没有歧义时,我们也常使用 “实体” 这个术语。
不同的实体类型可以通过名字和一组属性来区分。一个数据库里通常包含很多实体类型。
实体类型的图形化表示
每个实体类型都用一个标有名字的矩形表示,名字通常是名词。在 UML 中,每个实体名字的首字母是大写的 (如 Staff 和 PropertyForRent)。实体类型 Staff 和 Branch 的图形化表示如下图所示。
2. 联系类型
联系类型:实体类型间的一组有意义的关联。
一个 联系类型 是一个或多个实体类型间的一组关联。每个联系类型都被赋予一个能够描述其功能的名字。DreamHome Branch 中有个 POwns 的联系类型,它将 PrivateOwner 和 PropertyForRent 这两类实体关联起来。
与实体类型一样,也有必要区分 “联系类型” 和 “联系出现”。
联系出现:由参与该联系的各个实体类型的一个出现组成的可被唯一标识的关联。
一个 联系的实例出现 是指相互关联的多个实体的实例出现。本书使用术语 “联系类型” 或 “联系的实例出现”, 和术语 “实体” 一样,无歧义时,我们更多的是使用 “联系” 这个术语。
考虑联系类型 Has, 它表示 Branch 实体和 Staff 实体之间的一种关联,即 Branch Has Staff(分公司拥有员工)。Has 联系的每一个实例出现都将一个 Branch 实体的实例出现和一个 Staff 实体的实例出现关联在一起。可以使用 语义网(semantic net) 来表示联系 Has 的实例出现的个体。语义网是一种对象层的模型,它使用符号实心圆 “●” 表示实体,使用 “◈”表示联系。下图所示的语义网中,有三个 Has 联系的实例出现(分别标识为 r1、r2 和 r3)。每个联系都描述了某个 Branch 实体的实例出现和某个 Staff 实体的实例出现之间的关联。联系是使用连接参与实体(Branch 实体和 Staff 实体)的线来表示的。例如 r1 表示 Branch 的实体 B003 和 Staff 的实体 SG37 之间的关联。
注意,表示每个 Branch 和 Staff 实体的实例出现时,我们使用的是 Branch 和 Staff 的主关键字属性,即 branchNo 和 staffNo 的值。主关键字能唯一的标识每个实体的实例出现,在后面的小节中详细讨论。
如果使用语义网来表示某个企事业单位,将会陷入细节层面而难以理解。而是用实体联系(ER)模型的概念更容易标识企事业单位中实体之间的联系。ER 模型比语义网具有更高层次的抽象,这是因为 ER 模型将实体的实例出现集合组成实体类型,把联系的实例出现组合成联系类型。
联系类型的图形化表示
每个联系类型都表现为用现将相关的实体类型联系起来,并在线上标上联系的名字。通常用一个动词(如 Supervises 或 Manages)或者一个动词短语(如 LeasedBy)来命名一个联系。同样,联系名字的首字母也应大写。应该尽可能保证同一个 ER 模型中的联系名字是唯一的。
一个联系还应标记一个方向,这通常意味着这个联系的名字仅在一个方向上有意义(如 Branch Has Staff 要比 Staff Has Branch 有意义的多)。所以,一旦确定了联系的名字后,为了让读者能够理解联系的名字的意义,要在名字旁边加上一个箭头符号来表示联系的正确方向(如 Branch Has → Staff)。
2.1 联系类型的度
联系类型的度:参与联系的实体类型的个数。
包含在某个联系类型中的实体被看作该联系的 参与者 。一个联系类型的参与者的数目称为这个联系的 度。所以,联系的度表明了一个联系包含的实体类型的个数。度为 2 的联系称为 二元联系。
度数为 3 的联系称为 三元联系。度数大于 2 的联系称为 “复杂联系”。
复杂联系的图形化表示。
UML 用一个菱形符号表示度大于 2 的联系。联系的名字放在菱形内部,在这种情况下,与该名字相关联的方向箭头可以省略。三元联系 Registers 如下图所示,即本文开始 DreamHome 中的联系 Registers。
2.2 递归联系
递归联系:同一个实体类型以不同的角色多次(大于 1 次)参与了同一个联系类型,这种联系类型被称为递归联系。
考虑递归联系 Supervises, Supervises 表示了员工和某位主管之间的关联,而这位主管也是公司的一名员工。也就是说,实体类型 Staff 连词参与了联系 Supervises:第一次参与的角色是一位主管,第二次参与的角色是一位员工(被管理者)。递归联系有时也叫作一元联系。
可以添加 角色名称 来表明每一个参与联系的实体类型在该联系中的意义。在递归联系中,角色名称对于确定每个参与者的作用是非常重要的。下图表示了如何使用角色名称来描述 Supervises 联系,其中 Staff 实体类型第一次参与时的角色名称是 Supervisor,第二次参与时的角色名称是 Supervisee。
当两个实体之间存在多于一种联系时也可以使用角色名称。以下图为例,Staff 和 Branch 两个实体类型之间存在 Manages 和 Has 两种联系,此时添加角色名就能够标明每种联系的意义。具体来说,在 “Staff Manages Branch” 的联系中,Staff 实体中具有角色名称 “Manager” 的某位员工管理 Branch 实体中具有角色名称 “Branch Office” 的某一分公司。类似的,对于 “Branch Has Staff” 联系,角色名称为 “Branch Office” 的分公司雇佣角色名称为 “Member of Staff” 的员工。
当参与联系的实体在联系中的功能无二义时,通常不需要定义角色名称。
3. 属性
属性:实体或联系类型所具有的某一特性。
实体类型具有的特性称为属性。例如,实体类型 Staff 的属性有 staffNo、name、position 和 salary。属性被赋值以后就可以描述每个实体的实例出现,而属性值的集合则是数据库中所存储数据的主要构成。
关联实体的联系类型也可以具有和实体类型类似的属性,这部分内容在第五小节讨论。
属性域:单个属性或多个属性所允许的取值集合。
每个属性都与一个取值集合相关联,这个集合称为 域。域定义了一个属性可能的取值范围,这与关系模型中的域的概念类似。例如,每一个房屋实体所拥有的可出租房间数量从 1 到 15 不等,所以,实体类型 PropertyForRent 的属性 rooms(房屋数量)的取值范围是从 1 到 15 的任意整数。
多个属性可以共享一个域。例如,实体类型 Branch、PrivateOwner 和 BusinessOwner 都拥有属性 address,且这些属性的域也相同,即可以取所有可能的地址。域还可以由其他一些域组合而成。例如,实体 Branch 的 address 属性域可以由以下子域组成:street、city 和 postcode。
属性 name 的域更难定义,因为它包含了所有可能的名字:可以是一个字符串,不仅包括字母,还可能包括连字符 “-” 或其他一些特殊的符号。一个完整的数据模型应该包括 ER 模型中每一个属性的域。
如下所述,属性可以分为:简单属性 和 组合属性;单值属性 和 多值属性;导出属性。
3.1 简单属性和组合属性
简单属性:有独立存在的单个部分组成的属性。
简单属性不嗯能够在被划分为更小的部分,如 Staff 实体的 position 和 salary 属性就是简单属性。简单属性有时又称为 原子属性。
组合属性:由多个部分组成的属性,每个部分都可独立存在。
有些属性可以划分为更小的部分,而且这些更小的部分可以独立存在。例如,若 Branch 实体的 address 属性的值为(163 Main St,Glasgow, G11 9QX),则这个属性可以继续划分为 street、city 和 postcode 三个属性,这三个属性的取值分别为(163 Main St)、(Glasgow)、( G11 9QX)。
建模时,究竟是将 address 属性当做一个简单属性,还是作为组合属性由三个子属性 street、city 和 postcode 构成,依赖于在用户数据视图中提及属性 address 时,是将其视为一个整体还是由多个独立部分组合而成。
3.2 单值属性和多值属性
单值属性:在实体类型的每个实例出现都只取一个单值的属性。
大多数属性都是单值属性。例如,实体类型 Branch 的每个实例出现的分公司编号(branchNo)属性的取值都只有一个(如 B003),因此属性 branchNo 被看做单值的。
多值属性:对于实体类型的某些实例出现可能取多个值的属性。
对于实体的某些实例出现,某个属性可以有多个值。例如 Branch 实体类型的某些实例出现,属性 telNo 都可以有多个值(例如,编号为 B003 的分公司的电话号码为 0141-339-2178 和 0141-339-4439),所以在这个示例中,属性 telNo 就是多值得。多值属性的取值个数可能会有上限和下限的约束。例如,实体类型 Branch 的属性 telNo 可以取 1 到 3 个值,也就是说,一个分公司可能至少有一个电话号码,至多有 3 个电话号码。
3.3 导出属性
导出属性:属性的值是从相关的一个或一组属性(不一定来自同一个实体类型)的值导出来的属性。
有些属性的值是导出来的。例如,实体类型 Lease 的属性 duration 的值就是根据该试题类型的属性 rentStart 和 rentFinish 的值计算出来的。因此我们称属性 duration 为导出属性,其值就是从 rentStart 和 rentFinish 导出的。
在有些时候,某些属性的值是从同一试题类型得实例出现导出的。例如,实体类型 Staff 的总人数(totalStaff)属性,就是通过计算 Staff 实体类型实例出现的总的个数得到的。
导出属性可能还与来自不同实体类型的属性有关。例如,实体类型 Lease 的属性 deposit 的值就是从实体类型 PropertyForRent 的属性 rent 导出的。
3.4 关键字
候选关键字:能够唯一标识每个实体的实例出现的最小属性组。
一个候选关键字是一个最小属性组,它的值能够唯一的标识每个实体的实例出现。例如,属性分公司编号(branchNo)是实体类型 Branch 的候选关键字,对于每个分公司的实体的实例出现,其 branchNo 的值都是不同的。实体类型的每一个实例出现的候选关键字的值都是唯一的,这意味着候选关键字不能为空。例如,每个分公司都拥有一个唯一的编号(如 B003),而且绝不会有两个或两个以上的分公司具有相同的编号。
主关键字:被指定用来唯一标识实体类型的每个实例出现的候选关键字。
一个实体类型可能有多个候选关键字。为了便于说明,假设每位员工都拥有一个唯一的公司指派的员工编号(staffNo)和一个唯一的、一般由政府使用的社会保险号(National Insurance Number, NIN)。那么实体 Staff 就有了两个候选关键字,必须取其一作为主关键字。
实体主关键字的选择要考虑属性的长度(长度最小者优先),以及该属性在以后是否仍具有唯一性。例如,由企业分配的员工编号最多包含 5 个字符(如 SG14),而 NIN 最多包含 9 个字符(如 WL220658D)。所以我们选择 staffNo 作为实体类型 Staff 的主关键字,而 NIN 则被视为可替换关键字。
合成关键字:包括两个或两个以上的属性的候选关键字。
有些情况下,一个实体类型的候选关键字是由几个属性组成的,这些属性组合起来可以唯一标识每个实体的实例出现,但分开来却不可以。考虑实体 Advert,它由 propertyNo(房产编号)、newspaperName、dateAdvert 和 cost 四个属性。多家报纸可能在同一天刊登了多处房屋出租的广告。为了唯一标识每个 Advert 实体类型的实例出现,需要同时确定 propertyNo、newspaperName 和 dateAdvert 三个属性的值。所以,实体类型 Advert 有一个合成主关键字,该合成关键字包括 propertyNo、newspaperName 和 dateAdvert 三个属性。
属性的图形化表示
如果要在一个实体类型中显示它的属性,可以将表示实体的矩形分成两个部分。上面写实体名字,下面列出属性的名字。实体类型 Staff 和 Branch 及其相关属性的 ER 图如下图所示。
列出的第一个属性(属性组)应该是实体类型的主关键字(在已知的情况下)。可以用符号 {PK} 来标记主关键字属性(属性组)。在 UML 里,属性名字的首字母要小写,如果属性的名字中包含了不止一个单词时,则后面的没歌词的首字母都要大写(例如,address 和 telNo)。当某个属性属于某个合成关键字时,可以用部分主关键字符号 {PPK} 来标记。可替换关键字则用符号 {AK} 标记。上图中实体类型 Staff 的主关键字是属性 staffNo,实体类型 Branch 的主关键字是属性 branchNo。
对于一些简单的数据库系统来说,在 ER 图中把每个实体类型的所有属性都列出来是可能的。然而对于复杂的数据库系统来说,我们仅仅列出了每一个实体类型的主关键字属性组。当 ER 图中只显示主关键字属性(属性组)时,可以省略 {PK} 标记。
对于简单属性和单值属性,没有必要特别标记,所以我们只要在实体名字下面列出这些属性名即可。对于组合属性,可以在紧跟着组合属性名的下面一行开始以右缩进的格式列出紫属性名。例如,上图中的实体 Branch 和 address 属性就是一个组合属性,跟在 address 下面的是该属性的子属性:street、city 和 postcode。对于多值属性,要为其指明属性取值的个数范围。例如,若果将属性 telNo 的范围标记为 [1..*],则意味着 telNo 可有 1 个或大于 1 个的取值。如果精确的知道值的最大个数,则可以标记出属性的确切范围。例如,如果属性 telNo 最多有三个值,则可以标记为 [1..3]。
对于导出属性,在属性名前加上符号 “/”。例如,在上图中,实体类型 Staff 的导出属性被标记为 /totalStaff。
4. 强实体类型与弱实体类型
实体类型可以分为强实体类型和弱实体类型。
强实体类型:该实体类型的存在不依赖于其他的实体类型。
如果一个实体类型的存在不依赖于其它的实体类型,那么称这个实体类型为强实体类型。DreamHome ER图中的强实体类型包括:Staff、Branch、PropertyForRent 和 Client 实体。强实体类型的一个特征是可以使用该实体类型的主关键字唯一标识每个实体的实例出现。例如,可以使用实体类型 Staff 的主关键字 staffNo 属性唯一标识每个员工。
弱实体类型:该实体类型的存在依赖于其他实体类型的存在。
弱实体类型的存在依赖于其他实体类型的存在。下图中有一个弱实体类型 Preference。弱实体类型的一个特征是,仅使用该实体类型的属性无法唯一标识每个实体的实例出现。注意,实体 Preference 并没有主关键字,这意味着仅使用该实体的属性无法标识每个实体的实例出现。只有通过一个 Preference 的实例出现和某位客户之间的联系,才能唯一地标识每个 Preference 实体,而每个客户是可以用实体类型 Client 的主关键字 clientNo 唯一标识的。在这个例子中,Preference 实体的存在依赖于 Client 实体的存在,Client 实体被称为所有者实体(owner entity)。
弱实体类型有时也称为子(child)实体、依赖(dependent)实体或从属(subordinate)实体。强实体类型则称为父(father)实体、所有者实体或支配(dominant)实体。
5. 联系的属性
如第三小节所述,联系也可以具有属性。例如,DreamHome ER 图中的联系 Advertises,它将实体类型 Newspaper 和 PropertyForRent 关联起来。为了记录某处房屋出租广告的刊登日期以及广告的费用,可以把这些信息同 Advertises 关联起来,作为联系 Advertises 的属性——dateAdvert 和 cost,而不是把它们看作实体 Newspaper 或者 PropertyForRent。
联系的属性的图形化表示
在表示某个联系相关联的属性时,采用与实体类型相同的符号。但是,为了区分带有属性的联系与实体,将表示属性的矩形和联系用虚线连接起来。拥有属性dateAdvert 和 cost 的联系 Advertises 如下图所示。另外一个示例就是 DreamHome ER图中的拥有属性 mgrStartDate 和 bonus 的 Manages 联系。
对于拥有一个或多个属性的联系,意味着该联系隐蔽着一个未标识的实体类型。例如,联系 Advertises 拥有 dateAdvert 和 cost 两个属性,这可能意味着实体 Advert 的存在。
6. 结构化约束
下面分析参与联系的实体类型上可能存在的约束。这些约束应该反映出在现实世界中对这些联系的限制。这种约束的例子包括:要求可供出租的房产必须有一个业主,每个分公司必须有员工等。联系上主要的约束称为 多重性。
多重性(multiplicity):指一个参与实体类型通过某一联系与另一参与实体类型的某个出现发生关联的出现的数目(或者范围)。
多重性约束了实体间关联的方式,它是用户或企业建立的策略(或商业规则)的一种表示。识别并能够表示出所有适当的企业约束对于剑魔来说是非常重要的。
如前所述,最常见的联系的度是二元的。二元联系通常又可分为一对一(1:1)、一对多(1:*)或多对多(*:*)的。我们使用下面的完整约束来说明这三种联系:
- 一个分公司由一名员工管理(1:1)。
- 一名员工负责管理多出可供出租的房产(1:*)。
- 可以在多家报纸上刊登多处房屋出租的广告(*:*)。
注意:并不是所有的完整性约束都可以简单的用 ER 模型表示。例如,每一名员工每年都会由于在企事业单位工作而得到一天额外的休假,这样的约束是很难用 ER 模型表示的。
6.1 一对一(1:1)联系
考虑联系 Manages,它将实体类型 Staff 和 Branch 关联起来。下图用语义网给出了 Manages 联系类型的两个实例出现(分别标识为 r1 和 r2)。每个联系(rn)都表示了一个 Staff 实体的实例出现和一个 Branch 实体的实例出现之间的关联。我们用实体类型 Staff 和 Branch 主关键字 staffNo 和 branchNo 来标识每个 Staff 和 Branch 实体的实例出现。
多重性的确定
多重性的确定通常需要精确分析企业约束里给出的样本数据之间的联系。我们可以通过分析已经填好的表单或者报表来获取样本数据,如果可能的话,也可以通过和用户进行讨论来获取。但是,需要强调的是,只有当所分析和讨论的样本数据能够真实全面的反映建模所涉及的数据时,我们才能得到关于约束的正确结论。