数据库设计 - 通过外键有多少逻辑?

Database Design - How much logic via foreign keys?

这是一道关于数据库设计的理论题。我可以 "abuse" 关系作为数据库中的条件,或者我可以在源代码中使用传统的 if 条件。我将尝试用一个例子来解释我的问题:假设我们有两个表演角色(伪代码):

TABLE Human(
    int humanId PK,
    string name
);

TABLE Animal(
    int animalId PK,
    string species,
    string name
);

还有一组"actions"。对于给定角色可用的每个动作都必须定义。

TABLE Action (
    int actionId PK,
    string title
);

元组示例为

Human ( 78asd7, "Bob");
Animal ( fgh7df, "Dog", "Pluto");

Action ( d6guvs, "Eat");
Action ( hj5j6f, "Check_Self_Awareness");

我该如何实现,人和狗都可以 "Eat",但只有人可以 "Check_Self_Awareness"?

我看到两种可能性:

A) 通过外键解决:n:m表HumanActionsAnimalActions

TABLE HumanActions (
    int humanId FK,
    int actionId FK
);

HumanActions ( 78asd7 , d6guvs);
HumanActions ( 78asd7 , hj5j6f);

TABLE AnimalActions (
    int animalId FK,
    int actionId FK
);

AnimalActions ( fgh7df , d6guvs);

B) 用代码解决

if (type of DB_Tupel == "Animal" && action.title == "Eat") {
    // continue
}
if (type of DB_Tupel == "Animal" && action.title == "Check_Self_Awareness") {
    // error: animals don't have self awareness (except for apes)
}

你会推荐什么?

架构与标准

好吧,伟大的 EF Codd 博士(祝福他的名字)在 1970 年写了关系模型;自 1984 年以来,我们拥有真正的 SQL 平台;自 1987 年以来开放架构,自 1990 年以来作为标准。所以答案不仅仅是我的建议,不仅仅是最佳实践,而是标准所要求的。 IE。预期存在多年的组织的需求。

原则是将数据定义为数据库中的数据,包括管理数据的所有规则。这是完整性和一致性所必需的。它不是 "abuse"。数据库是一个单一的可恢复单元。规则和交易随数据库一起移动。

How much logic via foreign keys?

不是 "logic"。它是数据定义、管理数据的规则及其完整性。并且有比简单地通过外键更多的方法。

Non-architecture & Sub-standard

"Data rules implemented in code" 不仅是 sub-standard,它还产生了一个文件系统而不是数据库,它没有完整性,只能通过应用程序访问。那不是"closed architecture",那是non-architecture。落后于时代四十五年。大多数用户希望访问数据库而不受限于应用程序,例如。通过数百种报告工具中的任何一种。

但是 post-Codd "theoreticians" 声称为这个行业服务,OO/ORM 类型,写了关于如何实现原语的书籍,pre-relational,预1970 年代的 ISAM 记录归档系统,加上 object 的大量堆栈(实际上是塔),它们具有 none 的完整性、速度或 post-Codd 关系数据库的功能,并给它们贴上标签 "relational"。这就是他们所知道的,这就是他们所能做到的"teach"。

结果是,因为 RFS 不能做任何事情(不能做这个;不能做那个;不能支持层次结构;等等),并且因为 RFS 被标记为 "relational database" , 他们认为 关系数据库不能做这个、那个和其他事情 。无价之宝。

所以如果你想要一个关系数据库,大约在 1970 年定义的条款,大约 1984 年的实施条款,然后在数据中实施关于数据的规则。

  • HumanAction 是 Human

  • 的 child
  • AnimalAction 是 Animal

  • 的 child

记录 ID

ID 字段会让您很好地了解 1970 年代之前的 ISAM 文件,这些文件包含记录,而不是包含行的表格。 ID 是物理记录指针,而不是逻辑键。它们不具备键的特性,也无法提供关系键所提供的完整性。

  • 它不允许争论,因为根据 关系模型 中的定义,ID 字段不符合键的条件。使用 SQL 关键字 PRIMARY KEY 并不能神奇地将钥匙的品质赋予字段。

  • 如果要说关系型和 pre-relational DBMS 之间的区别,用一句话来说就是:

    在 pre-relational 中,DBMS 关系是使用 物理记录 ID 建立的,但在关系 DBMS 中,关系是使用 逻辑关系键建立的。

    因此,使用 ID 字段作为建立关系的方法,无疑是 pre-relational、物理的、non-logical、原始的。

  • 此外,每个ID字段(列暗示表,它们是文件,而不是表)建立了一个访问路径依赖关系,这在关系模型[=101中被明确禁止=].这保证了更多的加入,而不是根据神话更少的加入。

为了获得关系数据库,为了获得关系完整性、能力和速度,您需要关系键和关系规范化。去掉 ID 字段,选择自然键。然后,在 child 表中,键将被复合。这是 RDB 的标准票价,所有 SQL 平台都可以处理。习惯了。

相关数据

你所说的"abuse",由于你读过的书是马戏团怪人写的,是正常的,普通的引用完整性。这是最简单、最基本的层次。关系完整性远不止于此。但它从第一个基本级别开始。

因此您的表格将如下所示。目的是演示关系键。我至少需要三个级别来证明关系完整性(RFS 无法提供)。

Human Animal Activity Data Model

我们在这里说的是:

  • 不仅人类Activity是人类的child,而且

  • 人类Activity只存在于人类
    的语境中 (它不像在 RFS 中那样独立存在)

我知道你的表是一个例子,在实际情况下,它们会进一步规范化。例如。 Activity 将是一个 child 物种,而不是一个 实例 物种。

这具有各种体系结构优势,例如您的 object 现在更加简单,您不必处理 "inheritance" 或 "persistence" 数据。推论是,我已经证明了至少 40 次,无法更正或修复 object 层中的数据完整性问题,它们只能被定义为 to completion 在数据库本身中。

型号

那是一个IDEF1X模型。自 1993 年以来,IDEF1X 是关系数据库建模的标准。请注意,每一个小滴答;缺口;并做标记;鱼尾纹;实线与虚线;方角与圆角;意味着非常具体和重要的事情。参考IDEF1X Notation。如果您不理解符号,您将无法理解或工作模型。

UML,与它分开 不是 是一个标准,与它分开有一个单一的符号和一个 squillion ever-changing 符号,与它分开是事实上的free-for-all,不能像关系数据建模标准那样定义数据或数据中关系的复杂性。它根本没有丰富性。反之,你根本不知道自己错过了什么。

拒绝

如果您不喜欢这条消息,请开枪。好主意,九十九。除了(a)证明对我所暴露的问题的否认已经达到病态水平,(b)证明对马戏团怪胎的奴役,以及(c)明天会有另一个使者。

忽略你的具体例子,我认为这不是你问题的重点,你问的是是使用 table 驱动的逻辑 还是 硬编码逻辑.

这个问题没有简单的答案。一个并不总是比另一个更好,每个都有适合特定情况的优点。

Table 驱动的逻辑 在规则结构相对简单和一致,但规则的细节事先未知时很有用或者可以经常更改。

在您的示例中,新操作可能会定期引起人们的兴趣。发生这种情况时你想做什么?您是想在 ACTION table 中插入新行,还是想去触摸所有 IF/ELSE 语句?

硬编码逻辑 在规则结构为静态时非常有用,尤其是在规则非常复杂时。 Table 驾驶 算术运算顺序 没有多大意义,因为它们不会改变并且它们不适合自己 table-驱动。

每种方法都是一种技巧。你的目标应该是可靠的、清晰的、支持table 的代码。在每种情况下选择最能帮助您实现目标的方法。