Ecto уникальная ошибка ограничения на pkey

Я начал получать следующую ошибку при попытке вставить новую комнату

** (Ecto.ConstraintError) constraint error when attempting to insert struct:

    * unique: rooms_pkey

If you would like to convert this constraint into an error, please
call unique_constraint/3 in your changeset and define the proper
constraint name. The changeset defined the following constraints:

    * unique: rooms_name_index

Не должен ли автоинкремент первичного ключа? Что заставило бы эту ошибку произойти внезапно? Вставка сделана как часть мульти, с соответствующей частью:

|> Multi.insert(:room, Room.changeset(%Room{}, %{name: "service-user-care-team:" <> Integer.to_string(user.id)}))

Для дополнительной справки, вот моя схема, включая набор изменений

schema "rooms" do
  field :name, :string
  many_to_many :users, App.User, join_through: "user_rooms", on_delete: :delete_all
  has_many :messages, App.Message

  timestamps()
end

def changeset(struct, params \\ %{}) do
  struct
  |> cast(params, [:name])
  |> validate_required([:name])
  |> unique_constraint(:name)
end

А вот и миграция

defmodule App.Repo.Migrations.CreateRoom do
  use Ecto.Migration

  def change do
    create table(:rooms) do
      add :name, :string, null: false

      timestamps()
    end

    create unique_index(:rooms, [:name])
 end
end

3 ответа

Я выяснил, почему это происходит.

Важное замечание, которое я забыл включить в исходное описание, заключается в том, что это произошло во время работы в среде разработчиков.

Это связано с этим ответом. Ранее я вручную вставлял некоторые данные с помощью Postico, которые должны были явно включать идентификатор. Последовательность pkey не была обновлена ​​в тот момент, что позже привело к установке дублированного идентификатора.

ТЛ; др

замещать

|> unique_constraint(:name)

с

|> unique_constraint(:name, name: :rooms_pkey)

==============

unique_constraint не работает точно так, как вы ожидаете.

В приведенном вами примере атом :name передается в unique_constraint. Цитирование из документов:

По умолчанию имя ограничения выводится из таблицы + поля. Может потребоваться явно для сложных случаев

Вот почему набор изменений определяет :rooms_name_index хотя фактический индекс :rooms_pkey, Вы должны явно :name вариант, чтобы избежать этого поведения по умолчанию в экто.

Мой, вероятно, был нишевым случаем, но несколько лет назад у меня были записи, импортированные из другой таблицы с гораздо более высокими идентификаторами, которые в конечном итоге догнала моя версия postgres.

Мне пришлось выполнить изложенный здесь шаг Сброс счетчика автоинкремента в postgres , а именно запустить:

      ALTER SEQUENCE product_id_seq RESTART WITH X

непосредственно в базе данных postgres, чтобы сбросить счетчик идентификаторов в таблице продуктов.

Другие вопросы по тегам