我有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
(我认为这里的“感到”很糟糕。条目不属于异常,它只是一个异常),它将引发以下情况:** (Postgrex.Error) ERROR (not_null_violation): null value in column "exception_id" violates not-null constraint
table: entries
column: exception_id
我基本上想要首先创建一个Exception(如果它不存在),然后创建一个系统错误的新Entry,然后将先前遗忘的Exception作为关联放入该Entry中。
这是怎么了
最佳答案
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
关于phoenix-framework - 将Ecto模型与已经存在的模型作为关联插入,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36254866/