多态关系与每种类型的单独表

时间:2019-06-23 19:08:38

标签: mysql laravel database-design database-schema polymorphic-associations

我正在处理具有某些类型(例如UserAppointmentTask等)的数据库,每种类型可以具有零个或多个Notes

为实现这些关系,我可能遇到的解决方案是:

  1. 多态关系
  2. 每种类型使用单独的表

多态关系

很多人建议它是遵循Active Record模式的最简单的解决方案,并且似乎是最常见的框架实现,我将添加一个表,其数据为morphable

notable

我的notable_type可以让我区分User所涉及的类型(AppointmentTaskNote),而{{1 }}将允许我在相关的notable_id表中获得单独的type记录。

PROS:

  • 易于扩展,可以轻松地将更多模型与多态类关联
  • 限制表膨胀
  • 生成一个可以被其他许多类(DRY)使用的类

缺点

  • 随着数据的增长,更多的类型会使查询变得更加困难和昂贵
  • 不能有外键
  • 缺乏数据一致性

每种类型使用单独的表

或者,我可以为每种类型创建一个表,该表仅负责与该类型关联的typeNotes外键可以让我快速获取单个type_id记录。

user notes

许多在线上都将其视为一种代码味道,许多文章主张避免使用多态关系,而推荐使用替代形式(例如herehere)。

PROS:

  • 允许我们有效地使用外键
  • 高效的数据查询
  • 保持数据一致性

缺点:

  • 由于每种类型都需要一个单独的表,因此增加了表膨胀
  • 多个类的结果,每个类代表一个单独的type

想法

多态关系肯定是两个实施方案中较简单的一种,但是缺少外键约束,因此可能会出现一致性问题。

每个具有外键的type_notes关系(notesuser_notes等)的表似乎是正确的方法(与设计模式保持一致),但可能导致很多表(其他可能具有task_notes的{​​{1}}或类似于types的类型的附加[例如notes]。

感觉我的选择是简化表结构,但放弃外键并增加查询开销,或者增加具有相同结构的表数,但简化查询并允许外键。

鉴于我的情况,以上哪种更合适,还是我应该考虑替代方案?

2 个答案:

答案 0 :(得分:3)

什么是“膨胀”?您担心表格过多吗?我正在研究的许多实际数据库都具有100到200个表,因为这就是需要的。

如果您要添加多个表,那么为什么要分别为UserAppointmentTask使用单独的表?如果您具有User的多值属性,例如每个用户有多个电话号码,您会为电话创建一个单独的表,还是尝试以某种方式将它们全部合并到用户表中?还是为用户电话,约会受邀者和任务里程碑提供了一个多态的“属于其他事物的事物”表?

答案:不,您将创建一个Phone表,并使用它仅引用User表。如果约会有受邀者,则会获得自己的表(约会和用户之间可能是多对多)。如果任务具有里程碑,那也将获得自己的表。

正确的做法是像对应用程序中的对象类型进行建模一样,对数据库表进行建模。您可能想读一本SQL and Relational Theory: How to Write Accurate SQL Code 3rd Edition by C. J. Date之类的书,以了解有关表如何与类型相似的更多信息。

您已经本能地知道不能创建外键这一事实是一个危险信号。外键必须恰好引用一个父表。这应该是一个提示,即构造多态外键不是有效的关系数据库设计。一旦开始将表及其属性视为具体类型(如SQL和关系理论中所述),这将变得显而易见。

如果必须创建一个注释表,则可以使其引用一个称为“ Notable”的表,该表类似于UserAppointmentTask的超类。然后,这三个表中的每一个也将引用主键Notable。这模仿了多态的面向对象结构,您可以在其中拥有一个类Note可以通过其超类类型对对象进行引用。

但是恕我直言,这比需要的要复杂。我只是为UserNotesAppointmentNotesTaskNotes创建单独的表。我再也不用再拥有三个表了,这使您的代码更加清晰和可维护。

答案 1 :(得分:1)

我认为您应该先考虑这两件事,然后再做出决定。

  1. 性能。很多读,很多写?测试哪个更好。
  2. 模型的增长。可以轻松扩展吗?