Laravel和MySQL使用多态关联连接表

时间:2018-10-22 20:13:33

标签: mysql laravel polymorphic-associations

更新: 以下架构只是一个模块(注释)的简化示例,该模块需要与其他模块具有多态关系。该应用程序有许多模块(超过30个),用户可以通过admin添加新模块。因此,每个模块都可以“链接”到另一个模块,但是在编码时我们还不知道模块名称和表名称。因此,我们需要一个多态关系。

我正在尝试使用多态关联对动态表名称执行联接。

假设以下MySQL表

modules table
module_id | name    | table_name
1         | Quote   | quotes
2         | Order   | orders
3         | Product | products

注意:系统允许通过admin添加新模块,因此在编码时我们不知道表名和列名。对于现有模块,模块名称或table_name也可以随时间变化。

quotes table
id | name
22 | "Quote #Q-22"
23 | "Quote #Q-23"

orders table
id  | name
122 | "Order #O-122"
123 | "Order #O-123"

products table
id  | name
55 | "Product #P-55"
56 | "Product #P-56"

comments table
id | module_id | record_id | text
1  | 1         | 23        | hello
2  | 2         | 122       | big
3  | 3         | 55        | world

我想运行一个查询,该查询将返回以下行:

comments
id | name          | text
1  | Quote #Q-23   | hello
2  | Order #O-122  | big
3  | Product #P-55 | world

Laravel通过将ORM类名或表名直接存储在父表中来允许polymorphic relationship

这让ORM负责处理这种关系,据我所知,通常会附带一些性能价格。 我认为会有明显的性能下降的原因是:

  1. 过高的开销。对于数千行,它将为每个对象创建一个雄辩的对象。我喜欢Eloquent,但是在检索大量行时,它的性能远远不如理想。查询生成器更适合于此,但不支持多态。
  2. 由于关联是在口才级别完成的,因此我相信它将需要其他查询。我还没有对此进行测试,否则,Eloquent将如何知道要加入哪些表?我很高兴被误认为这一点。
  3. 有时还会导致其他维护问题,例如更新表名或更改ORM类名/命名空间(尽管对此有解决方案)。
  4. 这会绕过外键约束。

我通常不喜欢将表名或模型直接与记录表耦合的想法。 这种方法的另一个重要(至少对我而言)缺点是,它将数据库模式与应用程序紧密耦合。换句话说,就是依靠口才的“魔术”。如果我们在某个时候想利用Node.js,Python或GoLang(我们目前正在实现微服务架构),我们可能将无法使用它,而不得不重组代码和数据库。

我已经阅读了几篇其他文章和问题,例如this onethis one

我想到的一种方法是使用MySQL函数或存储过程来动态获取表名称并合并结果。我能够使用存储过程和函数来动态获取表名,但是似乎无法加入存储过程的结果。函数似乎也不能解决这个问题。

第二种方法是将记录名称保存在单独的表中。这对于获取整个记录(行情,订单等)不起作用,但是由于我只需要记录名称,因此它可以正常工作(当然具有适当的索引编制)。

record_name table
module_id | record_id | name
1         | 23        | Quote #Q-23
2         | 122       | Order #O-122
3         | 55        | Product #P-55

此方法有一些缺点-首先,它仅适用于获取选定的键(在这种情况下为名称)。第二点是它复制数据并违反其他数据库原则。最后,需要维护才能更新module_name表。

因此,我的问题如下-

  1. 是否有好的替代方法可以在数据库级别(MySQL)上对此关系建模,还是必须在应用程序级别上进行?
  2. MySQL存储过程或函数可以解决此问题吗?

1 个答案:

答案 0 :(得分:-1)

您的架构是错误的,当您检查comments.record_id的外键约束时,您会注意到。

修复外键约束,并且应该出现类似这样的内容:

comments table
id | quotes_id | orders_id | products_id | text
1  | 22        | null      | null        | Text comment
2  | null      | 122       | null        | Text comment
3  | null      | null      | 55          | Text comment

正确的数据库架构(关系)比Laravel /雄辩的魔术更为重要。实际上,更少的魔术更容易更好地使用。 您还应该考虑完全不使用这种数据库抽象,它不会使事情变得简单,只会带来问题。

一种不同甚至更好的方法是使用关系表:

- comments table
id | text
1  | hello
2  | world

- quote_has_comment table
quote_id | comment_id
22       | 1
(with constraint quote_id+comment_id beeing unique