无法使用Ecto.Multi更新记录

时间:2017-10-11 21:12:23

标签: elixir phoenix-framework ecto

我有一个博客应用,当有人更新帖子时,它会在新闻源表中添加一个条目。 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和 1.3与Absinthe

1 个答案:

答案 0 :(得分:1)

您的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事务失败,则返回4元素错误元组,而不是常规的2元素错误元组。所以改变你的case语句如下:

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