Repo.transaction not working in Ecto Multi

I have this schema:

schema "rooms_units" do
  field(:date_from, :utc_datetime)
  field(:date_to, :utc_datetime)
  belongs_to(:room, App.Room, primary_key: true)
  belongs_to(:unit, App..Unit)
end

In my function I am making list of changesets and pass the list to Multi.insert_all as the room_unit_changeset

Multi.new
|> Multi.insert_all(:room_units, Appr.RoomUnit ,room_unit_changeset)
|> Repo.transaction()

Multi.insert_all returns the output like this:

%Ecto.Multi{
  names: #MapSet<[:room_units]>,
  operations: [
    rooms: {:insert_all, App.RoomUnit,
     [
      #Ecto.Changeset<
        action: nil,
        changes: %{
          date_from: #DateTime<2016-11-03 13:23:00Z>,
          date_to: #DateTime<2016-11-03 13:23:00Z>,
          room_id: 9,
          unit_id: 14
        },
        errors: [],
        data: #App.RoomUnit<>,
        valid?: true
      >,
      #Ecto.Changeset<
        action: nil,
        changes: %{
          date_from: #DateTime<2016-11-03 13:23:00Z>,
          date_to: #DateTime<2016-11-03 13:23:00Z>,
          room_id: 10,
          unit_id: 14
        },
        errors: [],
        data: #App.RoomUnit<>,
        valid?: true
      >,
     ], []}
  ]
}

But Repo.transaction is not working. Returning the server error .
Any help will be much appreciated
thanks

Which exactly?

This is too generic. Can you show us the code that constructs the Ecto.Multi object?

The problem isn’t with the multi object. The ecto multi works fine if i pass single record like this:

Multi.new
  |> Multi.insert(:room_units,  hd(room_unit_changeset))
  |> Repo.transaction()

But insert_all not seems to be working. If you look at the ecto.multi_all result . In the map the action is set to nil. Which i think should be insert like this

%Ecto.Multi{
names: #MapSet<[:room_units]>,
 operations: [
   rooms: {:insert_all, App.RoomUnit,
    [
     #Ecto.Changeset<
    action: :insert,
    changes: %{
      date_from: #DateTime<2016-11-03 13:23:00Z>,
      date_to: #DateTime<2016-11-03 13:23:00Z>,
      room_id: 9,
      unit_id: 14
    },
    errors: [],
    data: #App.RoomUnit<>,
    valid?: true
  >,

My bad . I thought Ecto.insert_all receives the changesets .But it actually receives the maps. like Repo.insert_all().
On side note is there any function of ecto that supports this multiple chagesets list of maps?
Because i want to validate the params and then insert into the database .

Two possible approaches for dealing with your list of changesets:

  • transform it into a series of Multi.insert calls that are then all executed at the end. Note that this will execute one SQL query per changeset, different from the behavior of insert_all.
  • transform the changesets into structs using Ecto.Changeset.apply_changes and then pass the structs to insert_all.

In both cases, you’ll want to handle changesets with valid?: false carefully; apply_changes, for instance, doesn’t check validity.

2 Likes