我有2个模型,entries
:
schema "entries" do
belongs_to :exception, Proj.Exception
field :application, :string
end
exceptions
:
schema "exceptions" do
field :name, :string
end
迁移脚本:
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
我的目标是存储在另一个系统中发生的异常。我希望项目能够将每个异常存储在第二个表exception
中(如果它们尚不存在),然后将应用程序名称和异常ID存储在第一个表entries
中。 entries
中有1000条记录,exceptions
中有少数记录。
假设entry_params
使用此JSON格式:
{
exception: "NPE",
application: "SomeApp"
}
应该创建条目的方法:
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
这将打印出来:
** (ArgumentError) unknown assoc `exception` in `put_assoc`
如果我将entries
模型更改为使用has_one
而不是belongs_to
(我认为belongs_to"感觉"这里不好。一个条目不属于异常,它只是有一个例外)它抛出以下内容:
** (Postgrex.Error) ERROR (not_null_violation): null value in column "exception_id" violates not-null constraint
table: entries
column: exception_id
我想要的基本上首先创建一个Exception(如果它不存在),然后创建一个新的系统错误条目,并将先前生成的Exception作为关联放入条目中。
这里有什么问题?
答案 0 :(得分:4)
belongs_to :exception, Proj.Exception
应为belongs_to :exceptions, Proj.Exception
Ecto.Changeset.put_assoc(entries_changeset, :exception, exception)
应为Ecto.Changeset.put_assoc(exception_changeset, :entries, entries)
entries
架构:
schema "entries" do
field :application, :string
belongs_to :exceptions, Proj.Exception, on_replace: :nilify
end
exceptions
架构:
schema "exceptions" do
field :name, :string
has_many :entry, Proj.Entry, on_delete: :delete_all, on_replace: :delete
end
迁移脚本:
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
假设entry_params
使用此JSON格式:
{
exception: "NPE",
application: "SomeApp"
}
创建或更新exceptions
以及相关的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