清单上的ecto multi build_assoc

时间:2019-01-22 08:22:19

标签: elixir ecto

我想在带有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)

1 个答案:

答案 0 :(得分:1)

Ecto.Multi的命名不是在插入多个记录之后,而是在单个交易中将多个操作分组之后。

Ecto.Multi.insert_all/5,但与Repo.insert_all/3有相同的局限性,即无法插入多个表。 (此外,它不支持自动时间戳,还有其他一些限制。)

只需使用常规迭代Enum.each/2或类似的方法,根据需要生成任意数量的插入语句,然后将所有语句包装到事务中即可。


要将多个孩子收集到Ecto.Multi中,可以使用Enum.reduceEcto.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()