Ecto 中的双向关系和多态关联

Bidirectional relationships and polymorphic associations in Ecto

我有一个名为 :issues 的 table,我需要建立一个方法来 link 两个问题。我想创建一个名为 :links 的新 table,但由于我必须遵循的规则,我在设计 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.

更复杂的是其他 table 的存在 :stories:notes:milestones 因为我应该能够 link 记录来自 table 的记录来自另一个 table 或来自相同 table 且具有上述相同规则。

我还考虑过为每种 link 创建一个 table。例如,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

我必须为 StoryNoteMilestone 做同样的事情。我只是对如何设置迁移和引用感到困惑。我也不确定连接 tables 如何知道哪个 table 正在 linking 它们,以及我将如何按照上面的第四条规则建立双向关系。

双向链接可以像 2 个单向链接一样简单地建模,例如。为了在这种情况下强制执行数据完整性,您将不得不依赖应用程序级逻辑或数据库触发器(后者更可靠但维护成本更高)。

你在这里需要的多态性是一个有点棘手的问题。 Ecto 不像 Rails' ActiveRecord(和类似框架)那样支持多态关联。故意的,因为它是有代价的:破坏 FK 约束(结果是数据完整性较弱)和一些性能损失(乍一看可以忽略不计,但随着数据库的增长而受到伤害)。

Ecto "suggests" 至少有 3 个解决方案:

  1. 单个linkstable,多个外键
  2. 多个 <object>_links table 具有所谓的 Link 本身的抽象模式
  3. 单个 links table 与多个多对多连接 tables (issues_links, milestones_links, ...)

每个都有很多优点和缺点,一些查询具体等

此处进行了简要说明https://hexdocs.pm/ecto/Ecto.Schema.html#belongs_to/3-polymorphic-associations but I would also suggest referring to https://pragprog.com/book/wmecto/programming-ecto - 本书包含整个章节 (14),对问题进行了详细说明,并提供了上述所有可能的解决方案。假装是我自己的知识,只是复制粘贴到这里是不公平的:)