使用Ecto在事务中使用中间插入的结果

时间:2017-10-11 02:48:35

标签: transactions elixir phoenix-framework ecto

使用Ecto v2.2.6,Phoenix 1.3

我有一个博客应用。当用户创建Post时,它会插入Post表,然后获取该帖子的结果ID并将其插入Newsfeeditem表。理想情况下,我希望这可以作为交易发生。

(我正在使用Absinthe graphql,因此我对插入的返回必须是{:ok, post}

的形式

我有一个看起来像这样的工作函数:

  def create_post_add_newsfeed(%{
      title: title,
      content: content,
      user_id: user_id
    }) do

    case Repo.insert!(%Post{title: title, content: content, user_id: user_id}) do
      post ->
        case Repo.insert!(%Newsfeeditem{type: "user_creates_post", user_id: user_id, post_id: post.id}) do
          newsfeeditem ->
            {:ok, post}
          _ ->
            {:error, "Post not recorded in newsfeed"}
        end
      _ ->
      {:error, "Post not inserted"}
    end
  end

这段代码不是一个交易,它的回调很臭。 Ecto.Multi似乎是一个更适合在这里使用的工具,但我不知道如何获得Post插入的结果,以便我可以将其插入Newsfeed

我想做这样的事情

  def create_post_add_newsfeed(%{
      title: title,
      content: content,
      user_id: user_id
    }) do
    multi =
      Multi.new
        |> Multi.insert(:post, %Post{title: title, content: content, user_id: user_id})
        |> # Some intermediate step where I get the 'post' from the line above
        |> Multi.insert(:newsfeeditem, %Newsfeeditem{type: "user_creates_post", user_id: users_id, post_id: post.id})

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

知道如何解决这个问题吗?

1 个答案:

答案 0 :(得分:2)

您可以使用Multi.run/3。传递给Multi.run/3的函数将接收到参数的更改。您可以从中提取插入的post,并为Repo.insert内的Newsfeeditem发出Multi.run。该函数应返回{:ok, _}{:error, _},这正是Repo.insert返回的内容,因此您无需在函数内部执行任何操作。

Multi.new
|> Multi.insert(:post, %Post{title: title, content: content, user_id: user_id})
|> Multi.run(:newsfeeditem, fn %{post: post} ->
  Repo.insert(%Newsfeeditem{type: "user_creates_post", user_id: users_id, post_id: post.id})
end)