修改Ecto中的外键

Tho*_*pel 30 elixir ecto phoenix-framework

我有这个已经运行并向上游发送的原始迁移:

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])
Run Code Online (Sandbox Code Playgroud)

现在我希望将外键user_id改为级联删除,这样当用户被删除时,他的所有相关视频也将被删除.

我尝试过以下迁移:

alter table(:videos) do
  modify :user_id, references(:users, on_delete: :delete_all)
end
Run Code Online (Sandbox Code Playgroud)

但这会引发错误:

(Postgrex.Error) ERROR (duplicate_object): constraint "videos_user_id_fkey" for relation "videos" already exists
Run Code Online (Sandbox Code Playgroud)

如何根据我的要求制定将更改此外键的迁移脚本?


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
Run Code Online (Sandbox Code Playgroud)

这会在ecto尝试重新创建之前删除约束.

Max*_*rke 29

我不确定这是什么时候添加到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
Run Code Online (Sandbox Code Playgroud)

  • 目前 mysql 不支持它 - `(ArgumentError) MySQL 适配器不支持约束` (2认同)

Gaz*_*ler 18

您可以在调用之前删除索引alter:

drop_if_exists index(:videos, [:user_id])
alter table(:videos) do
  modify :user_id, references(:users, on_delete: :delete_all)
end
Run Code Online (Sandbox Code Playgroud)

相反的做法有点棘手:

execute "ALTER TABLE videos DROP CONSTRAINT videos_user_id_fkey"
create_if_not_exists index(:videos, [:user_id])
Run Code Online (Sandbox Code Playgroud)


Jes*_*ieh 8

我最终得到了以下解决方案:

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
Run Code Online (Sandbox Code Playgroud)

这会在ecto尝试重新创建之前删除约束

复制自问题.

  • 不应该使用`flush()`吗?`drop constraint(:videos,"videos_user_id_fkey")`应该有效. (2认同)

dot*_*aul 8

在Ecto SQL 3.4.3中:

“如果:from值为 a %Reference{},适配器将在修改类型之前尝试删除相应的外键约束。”

modify :user_id, references(:users, on_delete: :delete_all), from: references(:users)
Run Code Online (Sandbox Code Playgroud)

应该管用。在进行回滚时,我发现这可以清除 FK 并删除该列:

remove :user_id, references(:users)
Run Code Online (Sandbox Code Playgroud)