Изменение внешнего ключа в Ecto
У меня есть эта первоначальная миграция, которая уже запущена и отправлена вверх по течению:
create table(:videos) do
add :url, :string
add :title, :string
add :description, :text
add :user_id, references(:users, on_delete: :nothing)
timestamps
end
create index(:videos, [:user_id])
Теперь я хочу изменить внешний ключ на user_id
на каскадные удаления, чтобы при удалении пользователя все связанные с ним видео также были удалены.
Я пробовал следующую миграцию:
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
Но это вызывает ошибку:
(Postgrex.Error) ERROR (duplicate_object): constraint "videos_user_id_fkey" for relation "videos" already exists
Как я могу сформулировать миграцию script, которая изменит этот внешний ключ в соответствии с моим требованием?
UPDATE
У меня получилось следующее решение:
def up do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
end
def down do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :nothing)
end
end
это сбрасывает ограничение перед тем, как ecto пытается его воссоздать.
Ответы
Ответ 1
Вы можете отбросить индекс перед вызовом alter
:
drop_if_exists index(:videos, [:user_id])
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
Противоположность немного сложнее:
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
create_if_not_exists index(:videos, [:user_id])
Ответ 2
Я не уверен, когда это было добавлено в Ecto, но по крайней мере в 2.1.6 больше нет необходимости в сыром SQL. drop/1
теперь поддерживает ограничения (drop_if_exists/1
не поддерживает):
def up do
drop constraint(:videos, "videos_user_id_fkey")
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
end
def down do
drop constraint(:videos, "videos_user_id_fkey")
alter table(:videos) do
modify :user_id, references(:users, on_delete: :nothing)
end
end
Ответ 3
У меня получилось следующее решение:
def up do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
end
def down do
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
alter table(:videos) do
modify :user_id, references(:users, on_delete: :nothing)
end
end
это сбрасывает ограничение перед тем, как ecto пытается его воссоздать.
Скопирован из вопроса.
Ответ 4
Я не думаю, что это может быть достигнуто с помощью alter table
. Например, согласно этот ответ Postgres не позволяет изменять ограничения в инструкции alter table
. MySQL также не позволяет изменять ограничения.
Самый простой способ - удалить поле и добавить его обратно, если у вас нет данных. В противном случае вам нужно использовать raw SQL с execute