我有一个名为:issues
的表,我需要建立一种链接两个问题的方法。我曾考虑过创建一个名为:links
的新表,但是由于必须遵循的规则,在设计Ecto模式时遇到了一些麻烦:
1. Links should be two-way and be any of these types: ["blocked-by" | "blocking" | "relates-to"]
2. If Issue-A is blocked-by Issue-B, Issue-B should be blocking Issue-A
3. If Issue-A relates-to Issue-B, Issue-B should relates-to Issue-A
4. Creating a link on one issue should create a link on the linked issue, following rules 1 and 2.
使这进一步复杂的是其他表:stories
,:notes
,:milestones
的存在,因为我应该能够将一个表中的记录与另一个表中的记录或具有相同规则的同一个表中的记录链接起来以上。
我还考虑过为每种类型的链接创建一个表。例如,Issue
的更新模式将如下所示:
defmodule MyApplication.Issue do
use Ecto.Schema
@primary_key false
schema "issues" do
field(:issue_id, Ecto.UUID, primary_key: true)
has_many(:linked_issues, LinkedIssue)
has_many(:linked_stories, LinkedStory)
has_many(:linked_notes, LinkedNote)
has_many(:linked_milestones, LinkedMilestone)
end
end
并且我必须对Story
,Note
和Milestone
做同样的事情。我只是对如何设置迁移和引用感到困惑。我也不确定联接表如何知道哪个表正在链接它们,以及如何按照上述第四条规则双向建立关系。
例如,双向链接可以简单地建模为2个单向链接。在这种情况下,要增强数据完整性,您将不得不依赖应用程序级逻辑或数据库触发器(后者更加安全,但维护成本更高)。
这里需要的多态性是一个棘手的问题。 Ecto不像Rails的ActiveRecord(和类似框架)那样支持多态关联。有意地,因为它要付出代价:打破FK约束(结果数据完整性较弱)和一些性能损失(乍看之下可以忽略不计,但随着数据库的增长而受到损害)。
至少有3种Ecto“建议”的解决方案:
links
表,多个外键。<object>_links
本身的所谓抽象架构的多个Link
表links
,issues_links
,...)的单个milestones_links
表]每个都有很多优点和缺点,某些查询是特定的,等等。
[我建议参考https://pragprog.com/book/wmecto/programming-ecto-本书包含整章(14),详细说明了该问题以及上述所有可能的解决方案。假装是我自己的知识,只是在此处复制粘贴是不公平的:)