创建具有变更集的非关联记录

问题描述 投票:0回答:1

我正在为远程API创建本地数据库模式,但遇到一些问题。

# CatalogObject
schema "catalog_objects" do
  field :type, :string

  has_one :item_data, ItemData, foreign_key: :catalog_object_id
  has_one :item_variation_data, ItemVariationData, foreign_key: :catalog_object_id
end

# ItemData
schema "item_data" do
  field :name, :string
  ...

  belongs_to :catalog_object, CatalogObject
end

# ItemVariationData
schema "item_variation_data" do
  field :name, :string
  ...

  belongs_to :catalog_object, CatalogObject
end

# API Response
%{
  "id" => "UA3XRLH75LEFRXCF2YWEUKB",
  "item_data" => %{
    "name" => "NY Steak",
    "variations" => [
      %{
        "id" => "2DYQSRC4AUZGAMCFTCOD24Q",
        "item_variation_data" => %{
          "item_id" => "UA3XRLH75LEFRXCF2YWEUKB",
          ],
          "name" => "Regular",
        },
        "type" => "ITEM_VARIATION",
      }
    ],
  },
  "type" => "ITEM",
}

我可以基于item_dataITEM创建type,而create_catalog_object/1没任何问题,但是我不知道从variations中的数据开始,因为它们是应该转换为CatalogObject,且typeITEM_VARIATION

我想一次创建带有ItemData的Item CatalogObject和带有ItemVariationData的ItemVariation CatalogObject,但是由于put_assoccast_assoc不相关,所以我无法在ItemData.changeset中使用ItemDataItemVariation CatalogObject

是否有一种一次性创建所有记录的方法?

抱歉,如果我没有正确解释问题。

elixir phoenix-framework ecto
1个回答
0
投票

对此进行了思考之后,对您有用吗?

defmodule ItemData do
  use Ecto.Schema
  import Ecto.Changeset

  schema "item_data" do
    field :name, :string

    belongs_to :catalog_object, CatalogObject
    has_many :variations, CatalogObject
  end

  def changeset(item_data, params \\ %{}) do
    item_data
    |> cast(params, [:name])
    |> put_assoc(:variations, Map.get(params, :variations, []))
  end
end

defmodule ItemVariationData do
  use Ecto.Schema
  import Ecto.Changeset

  schema "item_variation_data" do
    field :name, :string

    belongs_to :catalog_object, CatalogObject
  end

  def changeset(item_data, params \\ %{}) do
    item_data
    |> cast(params, [:name])
  end
end

defmodule CatalogObject do
  use Ecto.Schema
  import Ecto.Changeset

  schema "catalog_objects" do
    field :type, :string

    # The on_replace option tells Ecto that it is okay to update these fields
    # with a put_assoc or cast_assoc in a changeset.

    has_one :item_data, ItemData, on_replace: :update
    has_one :item_variation_data, ItemVariationData, on_replace: :update
  end

  def changeset(item_data, params \\ %{}) do
    item_data
    |> cast(params, [:type])
    |> put_assoc(:item_data, Map.get(params, :item_data))
    |> put_assoc(:item_variation_data, Map.get(params, :item_variation_data))
  end
end

# Example for how to create a CatalogObject struct from your API response
catalog_object = %CatalogObject{
  type: "ITEM",
  item_data: %ItemData{
    name: "NY Steak",
    variations: [
      %CatalogObject{
        type: "ITEM_VARIATION",
        item_variation_data: %ItemVariationData{
          name: "Regular"
        }
      }
    ]
  }
}

# Wherever you want to create the CatalogObject
catalog_object
|> CatalogObject.changeset() 
|> Repo.insert()
© www.soinside.com 2019 - 2024. All rights reserved.