我有一个博客应用,当有人更新帖子时,它会在新闻源表中添加一个条目。 Post
和Newsfeed
架构如下:
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
答案 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