Reputation: 2443
I have main data and detailed data. I would like to insert both at one time.
-------
main
-------
id
name
-------
---------
detail
---------
id
main_id
name
---------
I'm using Multi transaction by ecto. However I have no idea how to insert at once.
main = [name: "zaku"]
details = [%{main_id: 1, name: "hoge"}, %{main_id: 1, name: "moja"},]
Multi.new()
|> Multi.insert(:main, Main.changeset(%Main{}, main))
|> Multi.insert(:detail, Detail.changeset(%Detail{}, details))
|> Repo.transaction()
The part in Detail insert does not work. How can I do for it?
Upvotes: 1
Views: 225
Reputation: 9558
I think your example here is similar to the solution for your other example, you just need to close the multiple queries with a call to the transaction/1
function:
alias Ecto.Multi
alias Ecto.Repo
user = get_user_params_from_form() # <-- or where-ever you are getting data
email = get_email_params_from_form()
Multi.new()
|> Multi.insert(:user, User.changeset(%User{}, user))
|> Multi.insert(
:email,
# Capture the id from the previous operation
fn %{
user: %User{
id: user_id
}
} ->
Email.changeset(%Email{user_id: user_id}, email)
end
)
|> Repo.transaction()
Personally, I don't find the Multi
stuff very easy to work with, so sometimes I favor this other syntax, where you can pass a function to the Repo.transaction/2 callback. Loosely, that looks something like this:
Repo.transaction(fn ->
with {:ok, thing1} <- create_thing1(attrs1) do
create_thing2(attrs2)
else
{:error, e} -> Repo.rollback(e)
end
end)
def create_thing1(attrs \\ %{}) do
%ThingOne{}
|> ThingOne.changeset(attrs)
|> Repo.insert()
end
def create_thing2(attrs \\ %{}) do
%ThingTwo{}
|> ThingTwo.changeset(attrs)
|> Repo.insert()
end
It should be pointed out that this pattern can be used to wrap any task in a transaction. E.g. if "thing2" is to interact with a 3rd party API, for example.
Upvotes: 0
Reputation: 120990
The insert of the child does not work because of transaction. When the insertion of Detail
is attempted, the parent does not yet exist.
One usually uses Ecto.build_assoc/3
to insert dependent records, or [not recommended!] you might get rid of the transaction and insert them one by one with two queries—this would work.
Upvotes: 2