建立一对一关系的正确方法是什么?

Joã*_*iva 4 database-design

想象一下以下情况:

> A person has a passport.
> A person *owns only* one passport.
> One passport can only *be owned by a single* person. 
Run Code Online (Sandbox Code Playgroud)

这是一对一关系的明显案例。为简单起见,我们假设一个人只有姓名,护照只有国籍。最让我烦恼的是,似乎每个人的做法都不一样。据我所知,可以采取四种策略来映射这种关系:

  1. 同一张桌子上的所有东西:

  1. 所有者端引用拥有端的外键。

在此处输入图片说明

  1. 两个表上的主键值相同。

在此处输入图片说明

  1. 拥有方的外键,顶部有一个唯一键:

在此处输入图片说明

  • 数字 1 是不言自明的,当实体很小时我没有看到任何问题,但是如果它们有很多字段,我们将有一个巨大的表。
  • 数字 2 看起来不错,这是我看到大多数人和框架这样做的方式(例如实体框架、Hibernate),这也是我在学校接受的教学方式。这里的大问题是,由于参照完整性,我们的删除逻辑将被颠倒。我应该可以毫无问题地删除护照,但在这种情况下,我将无法在不删除此人的情况下删除它,这没有任何意义。
  • 数字 3 和 4 看起来几乎相同。有了护照一侧的外键,我可以删除护照而不删除人,这是有道理的。如果我移除一个人,我应该必须移除他们的护照。我看到使用选项编号 4 而不是编号 3 或所有其他选项的主要优点是,如果出于任何原因我决定我现在希望用户拥有多本护照,我只需要删除唯一键约束,即与更改两个表中的键相比,非常简单,而且麻烦也少得多。

所以我的问题基本上被简化为以下内容:有了 4 号的这么多优势,为什么人们继续使用其他策略?我最大的把握是使用 ORM,例如 Hibernate,在我看来,它以相反的方式做事。Hibernate 跟踪的关系的拥有方是拥有数据库中外键的关系方。因此,如果我尝试在 Java 中使用 Hibernate 执行此操作,我的关系将被交换。如果我也像它想要的那样在 person 表上包含通行证的外键,它会破坏删除逻辑,就像我之前解释的那样。我的印象是 EF 也以这种方式工作。那么,有了所有这些,为什么人们仍然喜欢“不利”的方法呢?

Dam*_*vic 7

最重要的是精确地用词约束,不允许出现逻辑错误。选项 1、2、3 包含逻辑错误。选项 4 很接近,但可能不能很好地代表现实——一般来说,一个人可能拥有不止一本护照(双重国籍)。

选项 1是不现实的,因为它指出没有护照就不可能存在。

选项 2基本上允许护照在没有人的情况下存在。

选项 3声明护照是一个人。

选项 4是最接近的,可以表述为:

[P1]存在名为 (NAME) 的人员 (PERSON_ID)。

(c1.1)人由 PERSON_ID 标识。

(c1.2)每个人只有一个名字;对于每个名字,不止一个人可以拥有这个名字。

[P2]国家(COUNTRY)签发的护照(PASSPORT_ID)归个人(PERSON_ID)所有

(c2.1)护照由 PASSPORT_ID 标识。

(c2.2)每本护照恰好由一个国家签发;对于每个国家,该国可以签发不止一本护照。

(c2.3)每本护照仅由一人拥有;每个人最多可以拥有一本护照。

(c2.4)如果一个国家签发的护照归某人所有,则该人必须存在。

人 {PERSON_ID, NAME} -- p1
   密钥 {PERSON_ID} -- c1.1



护照 {PASSPORT_ID, COUNTRY, PERSON_ID} -- p2
     密钥 {PASSPORT_ID} -- c2.1
     密钥 {PERSON_ID} -- c2.3

外键 {PERSON_ID} REFERENCES 人 {PERSON_ID} -- c2.4

笔记:

[Px] = 谓词 x
[cx.y] = 约束 xy

KEY = PK 或 AK

PK = 主键
AKn = 备用密钥(唯一)
FKn = 外键

所有属性不为空

编辑

需要明确的是,如果您选择了不同的示例,则选项 3将是正确的选择。说,Person & EmployeeEmployee & Accountant而不是Person & Passport。因为员工是人,会计师是员工。这种is-a关系意味着一个适当的子集。

这是一个很好的例子,说明专注于技术细节可能会导致逻辑错误,并且没有小逻辑错误这样的事情。