Search⌘ K
AI Features

Run Transactions and Capturing Errors with Ecto.Multi

Explore how to use Ecto.Multi to group multiple database operations in Elixir, ensuring atomic transactions. Learn to manage operation results, handle errors with detailed feedback, and understand rollback behavior to write cleaner and safer database code.

The Ecto.Multi struct

The other way to use Repo.transaction is to pass in an Ecto.Multi struct rather than a function. The Ecto.Multi struct allows us to group our database operations into a data structure. When handed to the transaction function, the Multi’s operations run in order. If any of them fail, all of the others are rolled back.

Let’s take a look at an earlier example where we ran a transaction with an anonymous function.

Elixir
artist = %Artist{name: "Johnny Hodges"}
Repo.transaction(fn ->
Repo.insert!(artist)
Repo.insert!(Log.changeset_for_insert(artist))
end)

Here’s how we can rewrite it using Multi.

Elixir
alias Ecto.Multi
artist = %Artist{name: "Johnny Hodges"}
multi =
Multi.new\
|> Multi.insert(:artist, artist)\
|> Multi.insert(:log,Log.changeset_for_insert(artist))
Repo.transaction(multi)

There’s a lot here, so let’s walk through it.

A walkthrough

  1. We created a new Multi with the new function. The Ecto team recommends using this approach rather than trying to create the struct directly—don’t try to write something like multi = %Multi{}. The exact structure of Ecto.Multi is subject to future change. When we call new, it ensures that the struct will be properly initialized to us. If we create the struct directly, we’re on our own.

  2. We then add the two insert operations by piping the Multi into the insert function. The Ecto.Multi module has several functions that mirror ...