5

问题

我有一个files表,还有许多其他表可以创建一对一关联,例如users可能有 aavatarposts可能有photo.

一个可能的解决方案

一个可能的解决方案是创建users_filesposts_files表并使用has_one :through. 但是,这看起来有些过分。

理想的解决方案

理想的解决方案是定义这样的表

users
 - avatar_id

posts
 - photo_id

并有with:参数,has_one所以架构看起来像这样

schema "users" do
    has_one :avatar, MyApp.FileDb, with: :avatar_id, foreign_key: :id #id is default

end

schema "posts" do
    has_one :photo, MyApp.FileDb, with: :photo_id, foreign_key: :id

end

这样你就不需要定义 a belongs_toon files。是否已经有类似的机制?在凤凰城处理这个问题的标准方法是什么?

4

2 回答 2

10

您无法摆脱没有belongs_to,因为这是定义外键的地方。您有两种选择:

  1. 翻转关系,使用户和帖子都有一个指向文件表的 avatar_id 和 photo_id

  2. 在没有“files”表的情况下定义“users_files”和“posts_files”表。“users_files”和“posts_files”将具有完整的表结构,可以在 Ecto 的模型级别共享。我们实际上在 Ecto 文档中讨论了这种情况:http://hexdocs.pm/ecto/Ecto.Schema.html#belongs_to/3 参见多态部分)

于 2015-09-19T16:23:51.047 回答
0

我相信这里描述的是一个单向的一对一关联。files表格可用作头像、发布照片和许多其他内容的基表。如果您将files表设为“拥有”方,那么您最终会为每个具有文件关联的实体拥有一个 FK 列。

不幸的是,我相信如果您将 FK 放在头像上(通过使用belongs_to),那么您无法级联删除文件(这是为has_one侧面保留的)。因此,如果您删除头像,该文件现在是孤立的。理想情况下,头像不仅是关联的所有者(拥有 FK),而且还具有级联删除的能力。

无论如何,如果您不想将 FK 放在文件表上,那么您可以通过删除文件(而不是头像)来解决文件级联问题。它完成了工作,但它有点骇人听闻的感觉(主要是因为你说头像“属于”一个文件,而从域的角度来看,它实际上是相反的)。

例如Repo.delete(avatar),您将创建一个实际删除文件的删除函数,而不是使用 。在该功能中,您可以预加载文件,然后将其删除。这将级联删除头像(假设您has_one在文件架构中有,这不会影响数据库)。

例如:

def delete(%__MODULE__{} = avatar) do
  avatar
  |> Repo.preload([:file])
  |> Map.get(:file)
  |> Repo.delete()
  |> case do
    {:ok, _file} -> {:ok, avatar}
    {:error, changeset} -> {:error, changeset}
  end
end

值得注意的是,Doctrine 使用 和 之类的术语mappedByinversedBy避免这些 ORM/域命名冲突。诚然,这在 Ecto 中很少出现问题,我认为这可能更像是一个例外。

于 2018-02-14T23:51:27.203 回答