【问题标题】:How to model nested collection with one primary object如何使用一个主要对象对嵌套集合进行建模
【发布时间】:2011-08-14 02:53:25
【问题描述】:

我希望在 RDBMS 中模拟一个有多个提议时间的会议,但其中一个将被选为接受的或主要的。比如:

create table Meeting ( meetingId int );
create table ProposedTime( meetingId int, dateAndTime datetime );

但是,会有一个界面,用户可以在其中选择一个建议的时间,我需要保存该选择。

我能想到两个选项,每个选项都有缺点:

  1. 在会议表中保留选定的提案:

    create table Meeting( meetingId int, selectedProposalId int );
    create table ProposedTime( proposalId int PK, meetingId int, dateAndTime datetime );
    

    使用这种方法,selectedProposalId 可能用于属于不同会议的提案。

  2. 在所选提案上存储一个标志:

    create table Meeting(meetingId int);
    create table ProposedTime( meetingId int, dateAndTime datetime, isSelected bool );
    

    使用这种方法,可以将两个提案标记为选中。

我知道有“黑客”来确保完整性(对于 2,在 MS SQL 中,您可以使用过滤的唯一索引来确保只选择一个),但我宁愿不承诺供应商特定的代码。

我也可以只在应用层强制执行正确性,但这仍然让两个选项都保持打开状态。

你们有什么推荐的吗?如果有人有任何想法,我也愿意接受其他选择;)

注意:我使用的是 Rails 3,所以如果有使用 ActiveRecord 处理此问题的首选方法,我想听听。

【问题讨论】:

    标签: sql ruby-on-rails ruby-on-rails-3 data-modeling datamodel


    【解决方案1】:

    很好的问题。我喜欢你正在评估潜在的不一致的事实。在这种情况下,我认为第一个解决方案是正确的,只是做了一个小修改:ProposedTime 的主键应该是包含 meetingId 的复合主键。

    这有几个原因:首先,如果没有会议,proposedTime 显然不存在,更重要的是,如果没有特定的会议,它也不存在。从本质上讲,proposedTime 只能在会议的上下文中定义,因此它的定义不应允许它独立存在。

    其次,使用 meetingId 作为强制属性,这种依赖关系没有得到充分表达。例如,更新提议时间的 meetingId 字段是没有意义的。 “让我们把上午 9 点搬到另一个会议!”。将 meetingId 设为主键的一部分明确阻止了这种无意义的更新,因为更新后的主键本质上是另一回事。

    最后,proposedTime 具有逻辑上不完整的键这一事实是您在尝试正确使用它时遇到的第一件事。理想情况下,每个数据库关系都应该声明式一致。也就是说,如果你能表达“狮子有两个父母”的关系,那么一个父母应该不可能是松鼠。显然,性能和平台限制意味着你不能总是达到那个目标,但是这种不一致可以被视为一种“代码味道”,可能需要进一步调查。在您的情况下,修复似乎很小且性能良好。

    tl;dr:将 meetingId 添加到建议时间的 PK 中,然后使用您的第一个解决方案。

    【讨论】:

    • 我喜欢你的想法,但令人惊讶的是,我在实践中从未真正使用过复合主键。 proposalTimeId 仍然是一个身份,因此在整个表格中是唯一的吗?如果是这样,复合主键看起来很奇怪。或者,proposedTimeIds 是否在应用层生成,并且仅在会议中唯一?如果是这样,我担心安全地生成它们。或者有没有办法为每个 meetingId 独立播种身份列?
    • 考虑一个社交网站,其中用户通过电子邮件地址来识别。您可以轻松地制作这样的用户表:create table SocialUser( userId int PK, email varchar) 显然这会给您带来问题,因为同一封电子邮件可能会出现多次。然而你有一个唯一的主键!显然,PK 不足以真正识别唱片(听起来很奇怪)。正如我所看到的,您对提出的TimeId 的情况并没有那么不同。 proposalTimeId 提供唯一性,但缺少提供完整性所需的上下文。
    • 我为我的评论中可怕的格式道歉...我仍在学习标记语法!
    • 抱歉,我回复得太晚了 - stackoverflow 没有向我发送任何通知,我今天忘记查看网站了。我会接受你的建议,谢谢你的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-09-14
    • 1970-01-01
    • 1970-01-01
    • 2021-02-24
    • 1970-01-01
    相关资源
    最近更新 更多