Ecto Reload belongs_to 关联成功后 Repo.update
Ecto Reload belongs_to Association After Successful Repo.update
通过参数中的 parent_id
将给定 child
的关联从 parent_a
更改为 parent_b
会留下陈旧的 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
# ...
更新后检索新关联的父记录的正确方法是什么?
目前在 Ecto 中没有内置的方法可以做到这一点。您还遇到无法使用预加载的问题,因为关联已经预加载。
一个选项是:
%{child | parent: Repo.get!(Parent, child.parent_id)}
您也可以选择在调用 Repo.update
之前不调用预加载,这将阻止已经加载的关联。
强制预加载。默认情况下,Ecto 不会预加载已经加载的关联。
child
|> Child.changeset(params)
|> Repo.update!()
|> Repo.preload(:parent, force: true)
如果您想以不同的方式处理错误,则不使用 bang 更新
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
通过参数中的 parent_id
将给定 child
的关联从 parent_a
更改为 parent_b
会留下陈旧的 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
# ...
更新后检索新关联的父记录的正确方法是什么?
目前在 Ecto 中没有内置的方法可以做到这一点。您还遇到无法使用预加载的问题,因为关联已经预加载。
一个选项是:
%{child | parent: Repo.get!(Parent, child.parent_id)}
您也可以选择在调用 Repo.update
之前不调用预加载,这将阻止已经加载的关联。
强制预加载。默认情况下,Ecto 不会预加载已经加载的关联。
child
|> Child.changeset(params)
|> Repo.update!()
|> Repo.preload(:parent, force: true)
如果您想以不同的方式处理错误,则不使用 bang 更新
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