Ecto/Phoenix 上的多态性与 Rails 上创建的数据库

Polymorphism on Ecto/Phoenix with database created on Rails

我很难尝试在 Ecto 中实现多态性。我的主要问题是我正在尝试处理 Phoenix 中的多态关联,但是数据来自我们使用和创建的数据库——老实说,有点老了——主要应用程序,它基于 Rails。

其他机型都处理的很好,Rails和Phoenix这边读写数据都没有问题。

具有多态性的除外。我花了很多时间阅读 Ecto 的文档,我发现 "rails way" 不是 "right way" 但我有点卡在这里,因为我的模型已经写在 rails 上side(一些主题已经存储了数百万行)。

所以我在 Rails 中有这个抽象模型 element,它代表 7 tables(图像、视频、excel 等)。我还有另外两个 table,doc_imagesitems。另外两个 tables belongs_to element 因此具有 rails 魔法场 element_idelement_type。同样,postgres 中不存在 element table,只有 imagesvideos

我尝试在 Phoenix 中设置我的 imagesvideos 模型,但是当我将此代码放入我的 items 模式时:

  schema "items" do
    belongs_to(:video, Video, foreign_key: :element_id)
    belongs_to(:image, Image, foreign_key: :element_id)
    field(:element_type, :string)
    timestamps([{:created_at, :updated_at}])
  end

由于 (ArgumentError) field/association :element_id is already set on schema,我无法编译。

我可以手动执行所有查询,但我似乎无法正确编写模式。

最后,我需要能够使这些类型的查询正常工作(显然,除了 doc/video/image 部分外,所有这些都工作得很好):

MyApp.Repo.one(from t in Token,
      join: p in assoc(t, :project),
      join: vc in assoc(p, :vcard),
      join: th in assoc(p, :theme),
      left_join: z in assoc(p, :zip_archive), on: p.id == z.project_id,
      join: c in assoc(p, :company),
      join: b in assoc(c, :binfos),
      left_join: pi in assoc(p, :project_items), on: pi.id == pi.project_id,
      left_join: i in assoc(pi, :item),
      left_join: d in assoc(i, :doc),
      left_join: v in assoc(i, :video),
      left_join: im in assoc(i, :image),
      left_join: di in assoc(d, :doc_image),
      where: t.token_url == ^token_url,
      preload: [project: [:vcard, :theme, :zip_archive, [company: :binfos], project_items: [item: [doc: :doc_image, :video, :image]]]])

所以我的问题是:我还有哪些其他选择?我可以将列甚至其他 table 添加到我的数据库(并从其中现有的 table 迁移数据)但我无法从我的 [=53] 中删除 element 逻辑=] 应用程序(主要是为了时间问题,因为我团队中的其他人喜欢 Rails 方式 :p)。

有没有人能够以 Rails 的方式处理 Ecto 中的多态性,如果强烈反对的话?

我不会尝试复制 行为,而是采用最简单、最干净的解决方案。

删除 items 中的任何 belongs_to

schema "items" do
  field :element_id, :integer
  field :element_type, :string
  ...
end

changeset 添加验证,检查具有此 element_id 的相应 element_type 是否存在。

来自 Token

Select 加入了一切,除了 doc/image/etc 动物园。

Select 来自 element_type 作者 element_id

这肯定会起作用,尽管它意味着每个 select 和 upsert 都有一个额外的查询,但我相信结果代码的清晰度很快就会得到回报。

现在在不加入的情况下进行正常查询