sequelize の migrationで外部キー制約を貼り付けた時の undo 時の設定
TL;DR
removeConstraint
だけではなく removeIndex
も指定しよう。
どうして?
constraint
を導入した時に同時に index
が張られるので、 removeConstraint
だけすると index
が残ってしまうため。
気になる人は具体例を後ろの方に書いてあるのでそちらを参照。
正解の記述例
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return [
queryInterface.addConstraint(
'members',
['group_id'],
{
type: 'foreign key',
name: 'members_group_id_groups_fk',
references: {
table: 'groups',
field: 'id',
},
onDelete: 'cascade',
},
),
];
},
down: async (queryInterface, Sequelize) => {
return [
await queryInterface.removeConstraint('members', 'members_group_id_groups_fk'),
await queryInterface.removeIndex('members', 'members_group_id_groups_fk'),
];
}
};
実際にやってみる
スキーマ
例えば以下のような関係のテーブルがあったとする。
up する
それぞれのテーブルは既に create されているものとして、 members.group_id
の外部キー制約として groups.id
を設定したい場合、 up 時の記述としては以下のようになる。
addConstraint(
'members',
['group_id'],
{
type: 'foreign key',
name: 'members_group_id_groups_fk',
references: {
table: 'groups',
field: 'id',
},
onDelete: 'cascade',
},
)
sequelize db:migrate
実行後に SHOW CREATE TABLE members;
を発行すると以下のように、 contraint とさらに index が追加されていることがわかる。
CREATE TABLE `members ` (
`id` char(26) COLLATE utf8mb4_unicode_ci NOT NULL,
`group_id` char(26) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0',
`name` char(255) COLLATE utf8mb4_unicode_ci NOT NULL,
KEY `members_group_id_groups_fk` (`group_id`),
CONSTRAINT `members_group_id_groups_fk`
FOREIGN KEY (`group_id`) REFERENCES `groups` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
removeConstraint
だけ記述
down に removeConstraint('members', 'members_group_id_groups_fk')
だけ記述して sequelize db:migrate:undo
を実行し、SHOW CREATE TABLE members;
を発行して確認する。
CREATE TABLE `members ` (
`id` char(26) COLLATE utf8mb4_unicode_ci NOT NULL,
`group_id` char(26) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '0',
`name` char(255) COLLATE utf8mb4_unicode_ci NOT NULL,
KEY `members_group_id_groups_fk` (`group_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
バッチリ index が残っておりますな。
備考
addConstraint
の name は省略可
addConstraint
で name を書かない場合、自動的に key 名が生成される。
しかしそれだと removeConstraint
ができないので、適当なものを記述しておくと良い。
(書かずにやる方法はあるにはあるが、オススメするメリットはない)
await と順番
removeConstraint
と removeIndex
に await を指定している。
これは制約が解除されてからじゃないと index を剥がせないため。
await にするので、実行元の関数に async を指定するのを忘れずに。
実際にやってしまった人の対応策
残ってしまった index を手動で削除する MySQL 文は以下の通り。
ALTER TABLE [table_name] DROP INDEX [index_name];
Discussion