3

首先,我不确定如何准确搜索这个,所以如果它是重复的,请原谅。而且我什至不确定它是否更适合其他 StackExchange 站点之一;如果是这样,请告诉我,我会在那里问。无论如何...

项目概览

我正在做一个爱好项目——一个作家的笔记本——来练习编程和数据库设计。基本结构相当简单:用户可以创建笔记本,并在每个笔记本下创建与该笔记本关联的项目。也许笔记本是写一系列短篇小说的,而每个项目都是写一个单独的故事。

然后,他们可以将项目(场景、角色等)添加到笔记本中的特定项目或笔记本本身,使其与特定项目无关。这样,他们可以拥有跨越多个项目的场景或位置,以及具有特定于特定项目的一些场景或位置。

问题

我试图在数据库中保留大量的逻辑——如果可能的话,尤其是在表结构和约束中。我对很多项目的基本结构基本上是这样的(我使用的是 MySql,但这是一个非常普遍的问题——只是在语法上提到它):

CREATE TABLE SCENES(
    ID        BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL,
    NOTEBOOK  BIGINT UNSIGNED NULL,
    PROJECT   BIGINT UNSIGNED NULL,
    ....
);

问题是我需要确保至少设置了两个引用之一,笔记本和/或项目。不必同时设置它们——PROJECT 引用了它所在的 NOTEBOOK。我知道我可以有一个通用的“Parent Id”字段,但我不相信有可能有一个外国两张桌子的钥匙,对吧?还有可能添加额外的交叉引用表——即 SCENES_X_NOTEBOOKS 和 SCENES_X_PROJECTS——但这很快就会失控,因为我必须为我正在工作的每种不同的项目类型添加类似的表和。这也将引入确保每个项目在交叉引用表中都有一个条目的问题。

将这种逻辑放在存储过程或应用程序逻辑中很容易,但如果可能的话,我真的很想将它保持在某种约束中,以消除逻辑被绕过的任何可能性不知何故。

有什么想法吗?我几乎对任何事情都感兴趣——即使它涉及重新设计表格或其他东西。

4

2 回答 2

3

关于场景和人物的事情是作家可能会从他们当前的项目中删除它们。发生这种情况时,您不想丢失场景和角色,因为作者可能会在多年后决定使用它们。

我认为最简单的方法是重新定义它:

然后,他们可以将项目(场景、角色等)添加到笔记本中的特定项目或笔记本本身,使其与特定项目无关。

取而代之的是,想想这样说。

然后,他们可以将项目(场景、角色等)添加到笔记本中的用户定义项目或名为“未分配”的系统定义项目。“未分配”项目用于当前未分配给用户定义项目的事物。

如果你这样做,那么场景和角色将始终分配给一个项目——要么是一个用户定义的项目,要么是一个名为“未分配”的系统定义的项目。

于 2012-10-07T01:23:21.107 回答
2

我不清楚你到底有什么要求,但至少让我试着回答你的一些个人问题......

问题是我需要确保至少设置了两个引用之一,笔记本和/或项目。

检查(笔记本不为空或项目不为空)

我不相信有两个表的外键是可能的,对吧?

理论上,您可以从同一字段引用两个表,但这意味着这两个表都必须包含匹配的行。这可能不是你想要的。

你在正确的轨道上 - 让 NOTEBOOK 成为 FK 对一个表的子端点,而 PROJECT 对另一个表。不会强制使用 NULL 外键,因此您不必同时设置它们。

还有可能添加额外的交叉引用表——即 SCENES_X_NOTEBOOKS 和 SCENES_X_PROJECTS——但这很快就会失控,因为我必须为我正在工作的每种不同的项目类型添加类似的表和。

如果您正在谈论模拟多对多关系的联结(又名链接)表,那么是的 - 您必须为每对参与这种关系的表添加它们。

但是,您可以通过使用继承(又名类别、子类化、子类型、泛化层次结构...)来最小化此类表对的数量。想象一下,您有一组 M 个表,它们必须连接到第二组 N 个表。通常,您会创建 M*N 联结表。但是,如果您从一个公共父表继承第一个集合中的所有表,并对第二个集合执行相同的操作,那么您现在可以通过这两个父表之间的一个联结表将它们全部连接起来。

关于继承的完整讨论超出了这里的范围,但您可能想查看“ERwin 方法指南”、“子类型关系”一章以及这篇文章

将这种逻辑放在存储过程或应用程序逻辑中很容易,但如果可能的话,我真的很想将它保持在某种约束中,以消除逻辑被绕过的任何可能性不知何故。

你的直觉是正确的——让数据库尽可能地“保护”自己免受不良数据的影响。以下是确保数据正确性的优先顺序:

  • 表本身的结构。
  • 声明性数据库约束(域完整性、密钥完整性和引用完整性)。
  • 触发器和存储过程。
  • 中层。
  • 客户。

例如,如果您可以确保仅通过使用声明性数据库约束就必须遵循某个逻辑,则不要将其放入触发器中。

于 2012-10-07T00:39:57.417 回答