在ecto / phoenix / elixir中没有belongs_to的has_one

时间:2015-09-19 15:49:50

标签: elixir phoenix-framework ecto

问题

我有一个not表,还有许多其他表可以创建一对一的关联,例如files可能有usersavatar可能有posts

可能的解决方案

可能的解决方案是创建photousers_files表并使用posts_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 上定义belongs_to了。是否有类似的机制?在凤凰城处理这个问题的标准方法是什么?

2 个答案:

答案 0 :(得分:9)

你无法忘记没有belongs_to,因为那里定义了外键。您有两种选择:

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

  2. 定义" users_files"和" posts_files"没有"文件的表格#34;表。 " users_files"和" posts_files"将具有完整的表结构,可以在Ecto中的模型级别共享。我们实际上在Ecto文档中讨论了这个案例:http://hexdocs.pm/ecto/Ecto.Schema.html#belongs_to/3(参见多态部分)

答案 1 :(得分:0)

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

不幸的是,我相信如果你把FK放在头像上(使用belongs_to),那么就不能级联删除文件(为has_one方保留)。因此,如果删除头像,该文件现在是孤立的。理想情况下,化身不仅是协会的拥有者(拥有FK),而且还具有级联删除的能力。

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

例如,您不是使用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中很少成为一个问题,我认为这可能是一个例外。