我正在处理具有某些类型(例如User
,Appointment
,Task
等)的数据库,每种类型可以具有零个或多个Notes
为实现这些关系,我可能遇到的解决方案是:
很多人建议它是遵循Active Record模式的最简单的解决方案,并且似乎是最常见的框架实现,我将添加一个表,其数据为morphable
:
我的notable_type
可以让我区分User
所涉及的类型(Appointment
,Task
,Note
),而{{1 }}将允许我在相关的notable_id
表中获得单独的type
记录。
PROS:
缺点
或者,我可以为每种类型创建一个表,该表仅负责与该类型关联的type
。 Notes
外键可以让我快速获取单个type_id
记录。
许多在线上都将其视为一种代码味道,许多文章主张避免使用多态关系,而推荐使用替代形式(例如here和here)。
PROS:
缺点:
type
表多态关系肯定是两个实施方案中较简单的一种,但是缺少外键约束,因此可能会出现一致性问题。
每个具有外键的type_notes
关系(notes
,user_notes
等)的表似乎是正确的方法(与设计模式保持一致),但可能导致很多表(其他可能具有task_notes
的{{1}}或类似于types
的类型的附加[例如notes
]。
感觉我的选择是简化表结构,但放弃外键并增加查询开销,或者增加具有相同结构的表数,但简化查询并允许外键。
鉴于我的情况,以上哪种更合适,还是我应该考虑替代方案?
答案 0 :(得分:3)
什么是“膨胀”?您担心表格过多吗?我正在研究的许多实际数据库都具有100到200个表,因为这就是需要的。
如果您要添加多个表,那么为什么要分别为User
,Appointment
和Task
使用单独的表?如果您具有User
的多值属性,例如每个用户有多个电话号码,您会为电话创建一个单独的表,还是尝试以某种方式将它们全部合并到用户表中?还是为用户电话,约会受邀者和任务里程碑提供了一个多态的“属于其他事物的事物”表?
答案:不,您将创建一个Phone
表,并使用它仅引用User
表。如果约会有受邀者,则会获得自己的表(约会和用户之间可能是多对多)。如果任务具有里程碑,那也将获得自己的表。
正确的做法是像对应用程序中的对象类型进行建模一样,对数据库表进行建模。您可能想读一本SQL and Relational Theory: How to Write Accurate SQL Code 3rd Edition by C. J. Date之类的书,以了解有关表如何与类型相似的更多信息。
您已经本能地知道不能创建外键这一事实是一个危险信号。外键必须恰好引用一个父表。这应该是一个提示,即构造多态外键不是有效的关系数据库设计。一旦开始将表及其属性视为具体类型(如SQL和关系理论中所述),这将变得显而易见。
如果必须创建一个注释表,则可以使其引用一个称为“ Notable”的表,该表类似于User
,Appointment
和Task
的超类。然后,这三个表中的每一个也将引用主键Notable
。这模仿了多态的面向对象结构,您可以在其中拥有一个类Note可以通过其超类类型对对象进行引用。
但是恕我直言,这比需要的要复杂。我只是为UserNotes
,AppointmentNotes
和TaskNotes
创建单独的表。我再也不用再拥有三个表了,这使您的代码更加清晰和可维护。
答案 1 :(得分:1)
我认为您应该先考虑这两件事,然后再做出决定。