J'ai cette migration originale qui a déjà été exécutée et envoyée en amont:
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])
Maintenant, je souhaite changer la clé étrangère sur user_id
pour effectuer des suppressions en cascade, de sorte que lorsqu'un utilisateur est supprimé, toutes ses vidéos associées le soient également.
J'ai essayé la migration suivante:
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
Mais cela soulève une erreur:
(Postgrex.Error) ERROR (duplicate_object): constraint "videos_user_id_fkey" for relation "videos" already exists
Comment puis-je formuler un script de migration qui modifiera cette clé étrangère en fonction de mes besoins?
MISE À JOUR
Je me suis retrouvé avec la solution suivante:
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
cela supprime la contrainte avant qu'ecto n'essaye de la recréer.
Vous pouvez supprimer l'index avant d'appeler alter
:
drop_if_exists index(:videos, [:user_id])
alter table(:videos) do
modify :user_id, references(:users, on_delete: :delete_all)
end
Faire l'inverse est un peu plus délicat:
execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
create_if_not_exists index(:videos, [:user_id])
Je ne sais pas quand cela a été ajouté à Ecto, mais au moins dans 2.1.6 il n'y a plus besoin de SQL brut. drop/1
maintenant prend en charge les contraintes (drop_if_exists/1
pas si):
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
Je me suis retrouvé avec la solution suivante:
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
cela supprime la contrainte avant que ecto essaie de le recréer
Copié de la question.
Je ne pense pas que ce soit possible avec alter table
. Par exemple selon cette réponse Postgres ne permet pas de modifier les contraintes dans ALTER TABLE
déclaration. MySQL ne permet pas non plus de modifier les contraintes .
La chose la plus simple à faire serait de supprimer le champ et de l'ajouter à nouveau si vous n'avez pas de données. Sinon, vous devez utiliser du SQL brut avec execute