Hi, I’m learning Ecto and I am having a weird situation with INSERT query
Here are my models (import/alias are removed for clarity
defmodule MyModule.DataModel do
use Ecto.Schema
@primary_key {:id, Ecto.UUID, autogenerate: true}
@foreign_key_type :binary_id
schema "data_models" do
field :name, :string
belongs_to :project, Project
has_many :child_models, DataModelRelation, foreign_key: :target_id, on_replace: :delete
has_many :parent_models, DataModelRelation, foreign_key: :host_id, on_replace: :delete
timestamps()
end
defmodule MyModule.DataModelRelation do
use Ecto.Schema
@type_options ["Belongs To": :belongs_to, "Has Many": :has_many]
@primary_key {:id, Ecto.UUID, autogenerate: true}
@foreign_key_type :binary_id
schema "data_model_relations" do
field :type, Ecto.Enum, values: Enum.map(@type_options, fn {_, value} -> value end)
field :field, :string
belongs_to :host, DataModel
belongs_to :target, DataModel
timestamps()
end
And here is how I am creating the DataModel entry
defp create_data_model_entry(project_id, name, schema) do
%DataModel{}
|> DataModel.changeset(%{
project_id: project_id,
name: name,
schema: schema
})
|> Repo.insert()
end
defp create_model_relations({:ok, data_model}, child_models, parent_models) do
child =
Enum.map(child_models, &Map.put(&1, "host_id", data_model.id))
parent =
Enum.map(parent_models, &Map.put(&1, "target_id", data_model.id))
data_model
|> Repo.preload([:child_models, :parent_models])
|> DataModel.changeset(%{"child_models" => child, "parent_models" => parent})
|> IO.inspect()
|> Repo.update()
end
def create_project_data_model(
project_id,
%{"name" => name, "schema" => schema} = args,
_user_id \\ nil
) do
create_data_model_entry(project_id, name, schema)
|> create_model_relations(
Map.get(args, "child_models", []),
Map.get(args, "parent_models", [])
)
end
It’s working… kinda, except that the INSERT queries are wrong for the DataModelRelation table. I am able to create a new DataModel, correct amount of DataModelRelation rows but the data is wrong. For example, here are some INSERT statements
23:06:50.337 [debug] QUERY OK db=1.0ms
INSERT INTO "data_model_relations" ("type","field","host_id","target_id","id","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7) [:has_many, "relation1", "a25e6d4c-b5e5-4273-9500-063c4e8e1e0e", "a25e6d4c-b5e5-4273-9500-063c4e8e1e0e", "2b117b7b-7cf8-4c5b-8b00-4710c6be3681", ~N[2023-08-16 20:06:50], ~N[2023-08-16 20:06:50]]
↳ anonymous fn/3 in Ecto.Adapters.SQL.checkout_or_transaction/4, at: lib/ecto/adapters/sql.ex:1203
23:06:50.338 [debug] QUERY OK db=1.0ms
INSERT INTO "data_model_relations" ("type","field","host_id","target_id","id","inserted_at","updated_at") VALUES ($1,$2,$3,$4,$5,$6,$7) [:belongs_to, "relation2", "a25e6d4c-b5e5-4273-9500-063c4e8e1e0e", "a25e6d4c-b5e5-4273-9500-063c4e8e1e0e", "163f84c1-0a82-4190-a91a-c09734675565", ~N[2023-08-16 20:06:50], ~N[2023-08-16 20:06:50]]
and here is the IO.inspect()
output just before I call Repo.update()
#Ecto.Changeset<
action: nil,
changes: %{
child_models: [
#Ecto.Changeset<
action: :insert,
changes: %{
type: :belongs_to,
field: "relation2",
host_id: "a25e6d4c-b5e5-4273-9500-063c4e8e1e0e",
target_id: "0ee4fed3-0d5e-4d5b-8aec-42ac471aceb2"
},
errors: [],
data: #Kotini.Projects.DataModelRelation<>,
valid?: true
>
],
parent_models: [
#Ecto.Changeset<
action: :insert,
changes: %{
type: :has_many,
field: "relation1",
host_id: "aced1e16-d9a9-409a-a041-87242f4320ee",
target_id: "a25e6d4c-b5e5-4273-9500-063c4e8e1e0e"
},
errors: [],
data: #Kotini.Projects.DataModelRelation<>,
valid?: true
>
]
},
errors: [],
data: #Kotini.Projects.DataModel<>,
valid?: true
>
For some reason the host_id
and target_id
are always the same even though I specifically set them to different value. What I’m trying to achieve here is to model relationships between 2 DataModel rows, one row can have belongs_to/has_many relationship to different rows
I’m very new to Elixir so I might have missed something obvious
Thank you in advance!!!