在成功Repo.update成功后,重新加载Ecto关联归属

问题描述 投票:3回答:2
通过参数中的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 # ...

更新后检索新关联的父记录的正确方法是什么?
elixir phoenix-framework ecto
2个回答
2
投票
Ecto目前尚无内置方法来执行此操作。您还存在不能使用预加载的问题,因为关联已被预加载。

一个选项是这个:

%{child | parent: Repo.get!(Parent, child.parent_id)}

您也可以选择在调用Repo.update之后才调用预加载,这将防止关联已被加载。

2
投票
强制预紧。默认情况下,Ecto不会预加载已加载的关联。

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

© www.soinside.com 2019 - 2024. All rights reserved.