使用 Ecto.Multi 更新记录时遇到问题

Trouble updating a record with Ecto.Multi

我有一个博客应用程序,当有人更新 post 时,它会在新闻源 table 中添加一个条目。 PostNewsfeed 架构如下:

mix phx.new.json Content Post posts title:string content:string
mix phx.new.json Content Newsfeed newsfeeds message:string

这是包装函数:

  def updateContent(%{id: id, content: content}, _info) do
    post = Repo.get(post, id)
    Content.update_content_and_add_to_newsfeed(post, %{id: id, content: content})
  end

内容上下文中的逻辑如下:

  def update_content_and_add_to_newsfeed(post, %{id: id, content: content}) do
    multi =
      Multi.new
        |> Multi.update(:post, update_post(post, %{content: content}))
        |> Multi.insert(:newsfeed, %Newsfeed{message: "post updated"})

    case Repo.transaction(multi) do
      {:ok, %{post: post}} ->
        {:ok, post}
      {:error, _} ->
        {:error, "Error"}
    end
  end

这里是 update_post 函数:

  def update_post(%Post{} = post, attrs) do
    post
    |> Post.changeset(attrs)
    |> Repo.update()
  end

当我 运行 此代码时,数据库中的内容更新,但没有插入新闻源项目,我在控制台中看到此错误消息:

Server: localhost:4000 (http)
Request: POST /graphiql
** (exit) an exception was raised:
    ** (FunctionClauseError) no function clause matching in Ecto.Multi.update/4

知道如何解决这个问题吗?我正在使用 v2.2.6 and 1.3 和 Absinthe.

您的 Multi.update/4 调用不正确,因为它需要一个变更集。相反,您在交易之外更新 Post 并将更新结果传递给它。

记住,事务的目的是在出现错误时回滚。这意味着如果它失败了,所有的更改都应该被撤销(这在你的情况下不会发生)。


删除您的 update_post 方法,而只是传递变更集:

multi =
  Multi.new
    |> Multi.update(:post, Post.changeset(post, %{content: content}))
    |> Multi.insert(:newsfeed, %Newsfeed{message: "post updated"})

此外,如果 Ecto.Multi 事务失败,它 returns 是一个 4 元素错误元组,而不是常规的 2 元素错误元组。因此,像这样更改您的 case 语句:

case Repo.transaction(multi) do
  {:ok, %{post: post}} ->
    {:ok, post}
  {:error, _op, _value, _changes} ->
    {:error, "Error"}
end