Ecto.Multi [on_conflict: :nothing] behavior

Hey All!

I’ve got an Ecto.Multi.insert/4 that I’m using with on_conflict: :nothing. According to Ecto.Repo.insert/2's docs when a conflict occurs when using on_conflict: :nothing the resulting schemas id field should be nil. However, I’m seeing an id field with a value. When I remove the :on_conflict option I get a unique constraint error. When I get the count of number of records it does not change from before to after the transaction. So the record doesn’t seem to actually be getting created even though an id value is present.

Our primary keys are UUID. When we define a schema we set the @primary_key value to { :id, :binary_id, autogenerate: true }. So the database should be the one generating the keys.

Kind of at a loss.

Thanks!

The docs say:

id will be nil if the field is autogenerated by the database and no insert happened.

autogenerate: true is database dependent. For SQL databases, it is generated by Ecto and not the database. Luckily I just read an article that hows how to use pgcrypto to generate it in the DB: https://bernheisel.com/blog/ecto_changeset_tips/ :slight_smile:

1 Like

Thanks for the recommended reading.

Just FYI, we’re using Postgres with the uuid-ossp extension. All of our primary key definitions look like this.

add :id, :binary_id, default: fragment("uuid_generate_v4()"), primary_key: true

I’ll read the article you provided and see if I can come up with anything.

Thanks for the help!

Reading through Ecto.Schema's docs I saw this.

If you use the :id type with :autogenerate , it means the database will be responsible for auto-generation of the id.

Is this behavior different for :binary_id? I think I assumed :autogenerate set to true would make the database and not Ecto responsible for auto-generating the id.

After reading the article you provided I was able to figure it out.

Setting :read_after_writes to true instead of :autogenerate did the trick. Was confused by the documentation.

Thank you!

1 Like