我正在为远程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_data
为ITEM创建type
,而create_catalog_object/1
没任何问题,但是我不知道从variations
中的数据开始,因为它们是应该转换为CatalogObject
,且type
为ITEM_VARIATION。
我想一次创建带有ItemData的Item CatalogObject和带有ItemVariationData的ItemVariation CatalogObject,但是由于put_assoc
与cast_assoc
不相关,所以我无法在ItemData.changeset
中使用ItemData
或ItemVariation CatalogObject
是否有一种一次性创建所有记录的方法?
抱歉,如果我没有正确解释问题。
对此进行了思考之后,对您有用吗?
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()