我有一个not
表,还有许多其他表可以创建一对一的关联,例如files
可能有users
而avatar
可能有posts
。
可能的解决方案是创建photo
和users_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
了。是否有类似的机制?在凤凰城处理这个问题的标准方法是什么?
答案 0 :(得分:9)
你无法忘记没有belongs_to,因为那里定义了外键。您有两种选择:
翻转关系,以便用户和帖子都有指向文件表的avatar_id和photo_id
定义" 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使用
mappedBy
和inversedBy
等术语来避免这些ORM /域命名冲突。当然,它在Ecto中很少成为一个问题,我认为这可能是一个例外。