我希望在RDBMS中建立一个会议,该会议有几个建议的时间,但会选择一个作为已接受或主要的会议。类似的东西:
create table Meeting ( meetingId int );
create table ProposedTime( meetingId int, dateAndTime datetime );
但是,会有一个界面,用户可以选择其中一个建议的时间,我需要保存该选项。
我可以想到两个选项,每个选项都有一个缺点:
在会议桌中保留选定的提案:
create table Meeting( meetingId int, selectedProposalId int );
create table ProposedTime( proposalId int PK, meetingId int, dateAndTime datetime );
使用这种方法,selectedProposalId可能适用于属于不同会议的提案。
在所选提案上存储一个标记:
create table Meeting(meetingId int);
create table ProposedTime( meetingId int, dateAndTime datetime, isSelected bool );
通过这种方法,可以选择标记两个提案。
我知道有'hacks'来确保完整性(对于2,在MS SQL中你可以有一个过滤的唯一索引来确保只选择一个),但我宁愿不提交供应商特定的代码。
我也很好,只在应用程序层强制执行正确性,但仍然保持两个选项都打开。
你们推荐什么?如果有人有任何想法,我也愿意接受其他选择;)
注意:我正在使用Rails 3,所以如果有一种首选方法可以使用ActiveRecord来处理它,我想听听它。
答案 0 :(得分:1)
好问题。我喜欢你正在评估潜在的不一致性这一事实。在这种情况下,我认为第一个解决方案是正确的,只有一个小修改:ProposedTime的主键应该是包含meetingId的复合主键。
这有几个原因:首先,如果没有会议,提议的时间显然不会存在,更重要的是,如果没有特定的会议,它就不可能存在。基本上,除了会议的上下文之外,不能定义拟议的时间,因此它的定义不应该让它独立。
其次,使用meetingId作为强制属性,没有充分表达这种依赖关系。例如,更新proposedTime的meetingId字段是没有意义的。 “让我们早上9点搬到另一个会议!”使meetingId成为主键的一部分明确地阻止了这种无意义的更新,因为更新的主键本质上是另一回事。
最后,proposedTime具有逻辑上不完整的密钥这一事实是您在尝试正确使用它时遇到的第一件事。理想情况下,每个数据库关系都应该在声明上保持一致。也就是说,如果你能表达“狮子有两个父母”的关系,那么一个父母就不可能成为一只松鼠。显然,性能和平台限制意味着你不能总是达到这个目标,但这种不一致性可以被视为“代码味道”,可能值得进一步调查。在您的情况下,修复程序看起来很小并且性能很好。
tl; dr:将meetingId添加到proposedTime的PK中,然后使用第一个解决方案。