第一个图说明了 Has-a 关系。零件包含其他零件。发动机包含许多零件,其中一些是垫圈。
第二个图说明了 Is-a 关系。零件可以是发动机,也可以是垫圈,也可以是许多其他东西。
在抽象 ER 建模的世界中,Is-a 关系称为泛化-专业化。我说的是“抽象 ER 建模”,因为很多 ER 图真的描绘了一个关系模型,不管它看起来像什么。
当您从 ER 模型切换到关系模型时,事情开始变得有趣。
Has-a 关系很容易用关系术语建模。这实际上是关系建模 101。您将一个外键放在多侧,该外键在一侧引用一个主键,您就完成了。
Is-a 关系不是那么容易用关系术语建模。在对象建模中,这实际上是对象建模 101。您只需使用类和子类(有时称为类型和子类型),对象建模的继承特性将为您完成所有繁重的工作。
在关系建模中,事情并不那么容易。有一些众所周知的技术可以处理这种情况,但这些技术在关系建模教程中经常被跳过。有关其中一种技术的详细信息,我将向您推荐此标签下的标签 wiki: class-table-inheritance。
你会认为 ORM 工具会在这个领域大放异彩,但似乎没有。
编辑: 再次强调一点:ER 建模和表格设计不是同一个活动。一个人不会设计构成主题的实体和关系。人们通过研究主题,或者可能通过采访主题专家来发现实体和关系。然后设计表作为描述先前发现的实体和关系的所有数据值的方便容器。
在现实生活中,这可能是一个反复的过程。
现在让我们转向两种可能的表格设计来涵盖第二个图表。
第一个设计是 4-Table 设计。将有四个表:Part、Motor、Gasket 和 Motor_Gasket。四个主键将是 PartID、MotorID、GasketID 和 (MotorID, GasketID) 复合主键。
MotorID 不会通过自动编号填充。取而代之的是,当包含新电机时,应用程序将提供刚刚生成的 PartID 的副本。然后,MotorID 有双重职责:它在自己的表中用作 PK,也用作引用 PartID 的 FK。
GasketID 得到类似的处理。电机和垫圈共有的属性位于零件表的列中。其他属性酌情进入电机表或垫片表。
Motor_Gasket 表有两列:MotorId 和 GasketID。这些是引用相应表的 FK。此表的 PK 是整行。
现在 Motor_Gasket 表实现了 Contains 关系。PartID 与 MotorID 或 GasketID 之间的值的“继承”实现了“IS-A”关系。
另一种设计是两桌设计。
有两个表:Part 和 Motor_Gasket。
每个电机和每个垫圈都将在零件表中占据一行。将有一个名为 PartType 的列指定它是什么类型的部件。描述电机或垫片的所有属性都在零件表中。不适用的空格设置为 NULL。
Motor_Gasket 表有两列与以前完全相同,除了两列都引用了 Part 表(不同的行)。
这两种设计哪个更好?这取决于手头的情况。