ruby-on-rails Rails:如何在不触发外键检查(引用完整性检查)的情况下进行迁移?

nukf8bse  于 2023-11-20  发布在  Ruby
关注(0)|答案(1)|浏览(135)

我需要将所有表中所有主键的列类型更改为UUID
如何在不触发外键检查的情况下进行迁移?
我已经尝试了以下两种方法,但仍然会触发错误:

Mysql2::Error: Cannot change column 'id': used in a foreign key constraint 'fk_rails_6010a70481' of table 'project_development.some_other_table'

字符串

class JustAnotherMigration < ActiveRecord::Migration[7.0]

  def change
    ActiveRecord::Base.connection.disable_referential_integrity do
      change_column :cities, :id, :uuid
    end
  end

end


class JustAnotherMigration < ActiveRecord::Migration[7.0]

  def change
    ActiveRecord::Base.connection.execute "SET FOREIGN_KEY_CHECKS=0;"
    change_column :cities, :id, :uuid
    ActiveRecord::Base.connection.execute "SET FOREIGN_KEY_CHECKS=1;"
  end

end


Rails版本:7.0.4.3
MariaDB版本:11.1.2

hpxqektj

hpxqektj1#

不幸的是,你低估了改变主键类型的痛苦程度。如果你想改变主键类型,而不仅仅是改变数值类型,你必须首先更新所有相关的表,以避免这些表中的记录孤立。
该过程的概要是:
1.备份您的数据库。
1.创建一个cities.uiid UUID类型列。暂时不要触摸id列。
1.创建一个other_table.city_uuid列。它应该是可空的,现在可以跳过外键约束。
1.用cities.uiid填充other_table.city_uuid。这可以用OtherModel.include(:city).find_each { |om| om.update(city_uuid: om.city.uiid) }完成,也可以用UPDATE ALL和子查询或横向连接完成。前者对于小数据集足够了,后者会更快,因为它不会导致N+1个写查询。
1.现在,您已经完成了重新创建表之间的关系,删除other_table.city_id列。这将解决外键约束问题。
1.删除cities.id。这可能需要您首先删除索引。
1.从cities.uuidcities.id
1.将other_table.city_uuid转换为other_table.city_id,添加一个外键约束并使其不可空(如果适用)。
必须对模式中的每个外键列重复步骤3-5。

相关问题