数据库设计:循环引用

时间:2010-04-08 08:10:25

标签: database-design circular-reference

我有三个数据库表:

  • 用户
  • 电子邮件
  • 邀请

通过user_id字段将电子邮件链接到用户。

邀请也通过user_id字段链接到用户

可以在没有邀请的情况下创建电子邮件,但每个邀请都必须有电子邮件。

我想链接电子邮件和邀请表,以便能够找到特定邀请的电子邮件。

然而,这会创建一个循环引用,邀请和电子邮件记录都会保存同一用户的ID。

这是不好的设计,如果是这样,我怎么能改进它?

我的感觉是,使用外键和良好的业务逻辑,很好。

users
-----
id

emails
------
id
users_id

invitations
-----------
id
users_id
emails_id

5 个答案:

答案 0 :(得分:2)

这不是circular reference

如果电子邮件与邀请和邀请之间存在强烈的完整性关系,则可以将独立的完整关系重新发送回电子邮件(例如)。

编辑:关于设计

正如Henk Holterman所指出的那样,问题是你的设计是否达到normalized所需的程度。

指定表:主键,例如

用户:id
电子邮件:id,users_id
邀请:id,users_id,emails_id

并假设table_id字段上的外键没有对表放置其他约束(例如,只有一部分键是唯一的),那么您已建模以下内容:

  • 对于每个用户,可能有多封电子邮件,您无法收到没有相应用户记录的电子邮件
  • 对于每封电子邮件,可能会有多个邀请,您不能收到没有相应电子邮件或用户记录的邀请(注意:从上面的定义我们无法知道user_id是指电子邮件或用户中的条目)< / LI>

现在只有你可以说这些规则是否与您尝试建模的现实世界情况相对应。

查看数据库设计的一种方法是 - 实际上没有错误的数据库设计,您几乎总能找到可以使某些看起来像错误的数据合理的数据。这就是为什么不采用两种规则(以句子的形式)和表格(ER图,表格和关系的描述),不可能说设计中是否存在问题(尽管可以从个人经验中提出建议)。

为了说明 - 上面注意到不清楚哪个表user_id引用似乎很容易回答。考虑到您说每个邀请都有邮件,常见的答案是它应该从邮件表中引用user_id。

否则,可能存在邀请中记录的user_id和针对邮件记录的user_id不同的邀请。

通常情况下,这会使标有“标准化数据”的红灯闪烁在你的脑海中。但是,这里通常没有说出口的假设是email_id决定了user_id,这可能不是真的(!)。

这取决于数据的语义(每个表的谓词) - 例如,如果您正在尝试建模可以向一个人发送邀请并从另一个人收到电子邮件回复的情况(例如通过秘书邀请人们并接收直接回复),然后红灯关闭,一切都很好 - 这就是真正发生的事情,这就是你要在设计中允许的内容。

答案 1 :(得分:1)

我认为这里适当的正常形式是邀请邀请与电子邮件有FK关系而给用户。而且我认为这样可以正常工作。

在您的说明中,您声明邀请属于用户,但从约束条件来看,邀请属于电子邮件更为准确。

另一方面,你是对的,给予邀请UserId和EmailId都不是一个大问题。它也没有太大的优势。

答案 2 :(得分:1)

每个邀请都必须有电子邮件,但可以在没有邀请的情况下创建电子邮件。好的 - 但是可以在没有用户的情况下创建电子邮件吗?

  • 如果邀请必须有电子邮件 并且电子邮件也必须属于 用户,然后邀请是真的 与用户有关。在这种情况下,你的 目前的数据模型还可以 不需要添加任何字段 - 你 只需通过电子邮件加入邀请 用户ID。

  • 如果没有用户可以存在电子邮件, 然后他们独立于两者 用户和邀请。在这种情况下 你应该有一个“email-id”字段 在“用户”和“邀请”中 链接到“电子邮件”表。在 不过这种情况,你可能会结束 在用户拥有一个的情况下 电子邮件,他的邀请函有 单独(或重复)电子邮件。

答案 3 :(得分:1)

  

可以在没有邀请的情况下创建电子邮件,但每个邀请都必须有电子邮件。

invitationemailuser_id多少?如果没有,那么你的设计已经错了。

  

我想链接电子邮件和邀请表,以便可以找到特定邀请的电子邮件。   但是,这会创建一个循环引用,邀请和电子邮件记录都会保存同一用户的ID。

invitation user_id中的email是否指向email中的同一user_id,这一点尚不清楚。如果是这样,那么这是多余的,并且是一种否定。删除它,并使用unique constraint作为您的链接表返回email.(id, user_id)。如果您需要它来提高性能,请在id之间创建user_id(已经唯一,因为invited_user_id是您的主键),并且跨两列都创建一个外键。这样就可以在不牺牲数据完整性的情况下进行非规范化。

如果它是不同的 email.user_id,那么您可能希望稍微改进一下命名。类似于email.sent_by_user_id和{{1}}的内容会变为{{1}}。

答案 4 :(得分:1)

我认为你对所有答案都很满意,我不会以复数形式使用表名。

这是令人困惑和不必要的。

我分享了关于不属于邀请表的user_id的意见,但是如果您确定要在user_id和email_id之间建立强大的链接。

如果是这种情况,那么只需从邀请表中删除user_id,就没用了。