Insert Ecto model with already existing model as an association
I have 2 models, entries
:
schema "entries" do
belongs_to :exception, Proj.Exception
field :application, :string
end
And exceptions
:
schema "exceptions" do
field :name, :string
end
The migration script:
def change do
create table(:exceptions) do
add :name, :string, null: false
end
create table(:entries) do
add :exception_id, references(:exceptions), null: false
add :application, :string, null: false
end
end
My goal is to store exceptions that happen in another system. I want the project to be able to store each exception in the second table exception
if they are not already there and then store the application name and the exception id in the first table entries
. There will be 1000s of records in entries
and a handful in exceptions
.
Assuming entry_params
uses this JSON format:
{
exception: "NPE",
application: "SomeApp"
}
the method that should create the entries:
def create(conn, %{"entry" => entry_params}) do
exception = Repo.get_by(Exception, name: entry_params["exception"]) ||
Repo.insert!(%Exception{name: entry_params["exception"]})
changeset =
Entry.changeset(%Entry{}, entry_params)
|> Ecto.Changeset.put_assoc(:exception, exception)
Repo.insert!(changeset)
end
This will print out:
** (ArgumentError) unknown assoc `exception` in `put_assoc`
If I change the entries
model to use has_one
instead of belongs_to
(and I think belongs_to "feels" bad here. An entry does not belong to an exception, it just has an exception) it throws the following:
** (Postgrex.Error) ERROR (not_null_violation): null value in column "exception_id" violates not-null constraint
table: entries
column: exception_id
What I want basically to first create an Exception (if it does not exist) and than create a new Entry of a system error and put the previously begotten Exception in the entry as an association.
What is wrong here?
belongs_to :exception, Proj.Exception
should be belongs_to :exceptions, Proj.Exception
Ecto.Changeset.put_assoc(entries_changeset, :exception, exception)
should be Ecto.Changeset.put_assoc(exception_changeset, :entries, entries)
Attempted solution:
entries
schema:
schema "entries" do
field :application, :string
belongs_to :exceptions, Proj.Exception, on_replace: :nilify
end
exceptions
schema:
schema "exceptions" do
field :name, :string
has_many :entry, Proj.Entry, on_delete: :delete_all, on_replace: :delete
end
migration script:
def change do
create table(:exceptions) do
add :name, :string, null: false
end
create table(:entries) do
add :application, :string, null: false
add :exception_id, references(:exceptions)
end
end
Assuming entry_params
uses this JSON format:
{
exception: "NPE",
application: "SomeApp"
}
create or update the exceptions
and the associated entries
:
def create(conn, %{"entry" => entry_params}) do
new_entry = Entry.changeset(%Entry{}, entry_params)
changeset =
case Repo.get_by(Exception, name: entry_params["exception"]) do
:nil ->
exception = %Exception{name: entry_params["exception"]} |> Repo.insert!
Ecto.Changeset.build_assoc(exception, :entries, [new_entry])
struct ->
changeset = Ecto.Changeset.change(struct)
data = Ecto.Changeset.preload(changeset, :entries) |> Map.get(:model) # Ecto 1.x
# data = Ecto.Changeset.preload(changeset, :entries) |> Map.get(:data) # Ecto 2.0.x
Ecto.Changeset.put_assoc(changeset, :entries, [new_entry | data.entries])
end
Repo.insert!(changeset)
end
链接地址: http://www.djcxy.com/p/90988.html
上一篇: Swift 2.2泛型的问题(Xcode 7.3)
下一篇: 将已有模型的Ecto模型插入为关联