成功Repo.update后,Ecto Reload belongs_to Association

时间:2016-01-22 11:21:23

标签: elixir phoenix-framework ecto

通过参数中的child更改给定parent_aparent_bparent_id的关联会留下陈旧的record.parent对象。

e.g。 (假设params匹配%{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
# ...

更新后检索新关联的父记录的正确方法是什么?

2 个答案:

答案 0 :(得分:3)

目前在Ecto中没有内置的方法可以做到这一点。您还遇到了无法使用预加载的问题,因为关联已经预先加载。

一种选择是:

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

您也可以选择在调用Repo.update之后再调用preload,这样可以防止已经加载关联。

答案 1 :(得分:0)

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

child
|> Child.changeset(params)
|> Repo.update!()
|> Repo.preload(:parent, force: true)

在更实际的示例中使用错误处理

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