child
将给定parent_a
的关联从parent_b
更改为parent_id
会留下陈旧的record.parent
对象。例如(假设参数匹配%{child: %{id: '1', parent_id: '6'}}
)
# ...
child = Repo.get(Child, child_id)
|> preload([:parent])
changeset = Child.changeset(child, child_params)
case Repo.update(changeset) do
{:ok, child} ->
IO.puts child.parent_id # returns '6', or the new, changed `id`
IO.puts child.parent.id # returns '5', or the old id
# child.parent is stale
# ...
更新后检索新关联的父记录的正确方法是什么?
一个选项是这个:
%{child | parent: Repo.get!(Parent, child.parent_id)}
您也可以选择在调用Repo.update
之后才调用预加载,这将防止关联已被加载。
child
|> Child.changeset(params)
|> Repo.update!()
|> Repo.preload(:parent, force: true)
或者如果您想以不同的方式处理错误,则不进行重大更新
child |> Child.changeset(params) |> Repo.update() |> case do {:ok, child} -> {:ok, Repo.preload(child, :parent, force: true)} error -> error end
在一个带有错误处理的更现实的示例中,它可能看起来像
with {:ok, child} <- get_child(child_id), {:ok, child} <- update_child(child, params) do # Do stuff else {:error, %Ecto.Changeset{} = changeset} -> # Handle error {:error, reason} -> # Handle error end defp get_child(child_id) do case Repo.get(Child, child_id) do nil -> {:error, :not_found} child -> {:ok, child} end end defp update_child(child, params) do updated_child = child |> Child.changeset(params) |> Repo.update!() |> Repo.preload(:parent, force: true) rescue error in Ecto.InvalidChangesetError -> {:error, error.changeset} error in RuntimeError -> {:error, error.message} end