我想在带有has_many
的多事务中插入列表。像
Ecto.Multi.new()
|> Ecto.Multi.insert(:main, Main.changeset(%Main{}, attrs))
|> Ecto.Multi.insert(:child, fn %{main: main} ->
Ecto.build_assoc(main, :child, %{name: "aaa"}) # inserts just one
end)
|> Ecto.Multi.run(:child, fn _, %{main: main} ->
Enum.map(attrs.children, &create_child/1) # doesn't return a multi and doesn't build the assoc
end)
|> Repo.transaction()
正如我评论的那样,我找不到可行的解决方案。
|> Ecto.Multi.insert(:child, fn %{main: main} ->
Ecto.build_assoc(main, :child, %{name: "aaa"})
end)
这仅插入一行,我要插入一个列表。
|> Ecto.Multi.run(:child, fn _, %{main: main} ->
Enum.map(attrs.children, &create_child/1)
end)
这不会返回multi,也不会使用main
构建assoc。
我也找到了这种形式,但也可以用于单个插入:
|> Multi.run(:user, fn %{organisation: organisation} ->
User.changeset(User, user_params)
|> Ecto.Changeset.put_assoc(organisation)
|> Repo.insert # returns a {:ok, user} or {:error, changeset}
end)
答案 0 :(得分:1)
Ecto.Multi
的命名不是在插入多个记录之后,而是在单个交易中将多个操作分组之后。
有Ecto.Multi.insert_all/5
,但与Repo.insert_all/3
有相同的局限性,即无法插入多个表。 (此外,它不支持自动时间戳,还有其他一些限制。)
只需使用常规迭代Enum.each/2
或类似的方法,根据需要生成任意数量的插入语句,然后将所有语句包装到事务中即可。
要将多个孩子收集到Ecto.Multi
中,可以使用Enum.reduce
和Ecto.Multi
作为累加器。
multi =
Ecto.Multi.new()
|> Ecto.Multi.insert(:main, Main.changeset(%Main{}, attrs))
attrs.children
|> Enum.reduce(
multi,
&Ecto.Multi.insert(&2, :child, create_child(&1))
)
|> Repo.transaction()