【问题标题】:Polymorphic has_many in EctoEcto 中的多态 has_many
【发布时间】:2017-05-22 22:02:34
【问题描述】:

我已经阅读了很多关于 polymorphic associations in Ecto 的内容,并且我同意在您的表之间拥有本机数据库引用是有利的观点。

然而,大多数时候多态 belongs_to 被引用,而不是相反 (has_many)。我仍然不确定如何正确处理它。

就我而言,它是关于 Phoenix 后端 API,我有一个 Page 模型,它有多个 Widgets。每个小部件都有自己的表和模型,因为它需要存储和返回不同的字段。假设我们有一个TwoColumnWidget 和一个ThreeColumnWidget,它们都有page_idPage 模型的引用。

我将如何理想地对此进行建模,现在我有一个中间 Widget 模型(带有数据库),它有一个用于每种可能的小部件类型的列,并选择其中一个列中存在 id 的那个。这对我来说感觉很 hacky,因为我必须在数据库中为每个需要同步的小部件存储额外的一行,以及为每个具体小部件获取正确的序列化程序/视图的麻烦。

由于我的域有很多这些类型的关系,我想找到一个更好的解决方案来简化进一步的开发。有什么指点吗?

【问题讨论】:

  • 当你说“自带数据库”时,你真的是我一个完整的数据库,还是“自带表”?

标签: elixir phoenix-framework ecto


【解决方案1】:

假设您的意思是每种小部件类型都有自己的表(模式),我会回答这个问题。由于您似乎在小部件和页面之间具有一对多关系而不是多对多关系,因此您可能需要考虑一个简单的地图数组方法,假设您使用支持它的数据库,如 postgress。

您需要注意,映射是使用字符串键而不是原子键持久保存在数据库中的。所以,如果我们将一个结构保存到数据库,当你读回它时,它将是一个带有字符串键的映射。所以你需要把它重新转换成这样的地图:

defmodule MyApp.Utils do

  def cast(%{} = schema, params) do
    struct schema, map_to_atom_keys(params)
  end
  def cast(module, params) when is_atom(module), do: cast(module.__struct__, params)

  def map_to_atom_keys(%{} = params) do
    Enum.reduce(params, %{}, fn({k, v}, acc) ->
      Map.put(acc, to_atom(k), v)
    end)
  end

  defp to_atom(key) when is_atom(key), do: key
  defp to_atom(key) when is_binary(key), do: String.to_existing_atom(key)

  def item_type(%{} = item), do: item_type(item.__struct__)
  def item_type(item) do
    Module.split(item)
    |> Enum.reverse
    |> hd
    |> to_string
  end
end

您可以对小部件表执行类似操作,其中可变数据存储为地图。如果存储结构名称,则可以将其转换回结构。

defmodule Widget do
  schema "widgets" do
    field :embedded_type, :string
    belongs_to :page, Page
    field :widget, :map
  end

  def changeset(struct, params) do
    struct
    |> cast(params, [:embedded_type, :page_id, :widget])
    |> handle_widget(params)
  end
  defp handle_widget(changeset, %{widget: widget}) do
    changeset
    |> put_change(:embedded_type, widget.__struct__ |> inspect)
  end
end

然后您可以使用上面的代码将其转换回来。

您还可以使用 Embedded_schema 创建每个小部件类型,并使用 Ecto 为您进行转换。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-23
    • 1970-01-01
    • 1970-01-01
    • 2011-03-13
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多