Express.js(ejs) + Sequelize(MySQL)でrailsのscaffoldアプリを作る の記事を参考に User (親) と 各 User に紐付く Comment (子) の構成を持つアプリケーションを作りました。
このアプリケーションにて、親の User を削除した際に、その User に紐付く子の Comment 群も削除する Cascade 削除を行う方法でハマったので記録します。
環境
- Node.js: v10.5.0
- Express.js: 4.16.0
- Sequelize: 4.0.0
- MySQL: 5.6.40
採用した方法 ( migration の addConstraint で cascade 定義する )
migration の addConstraint で cascade 定義した foreign key を設定します。
まず、 migration を新規作成します。
$ sequelize migration:create --name AddConstraintToComment
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
/*
Add altering commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.createTable('users', { id: Sequelize.INTEGER });
*/
return Promise.all([
queryInterface.addConstraint('Comments', ['user_id'], {
type: 'foreign key',
name: 'fk_comments_users',
references: {
table: 'Users',
field: 'id'
},
onDelete: 'cascade',
onUpdate: 'cascade'
})
]);
},
down: (queryInterface, Sequelize) => {
/*
Add reverting commands here.
Return a promise to correctly handle asynchronicity.
Example:
return queryInterface.dropTable('users');
*/
return queryInterface.removeConstraint('Comments', 'fk_comments_users');
}
};
addConstraint のオプションで onDelete : 'cascade'
を指定するところがポイントです。
migration を実行します。
$ sequelize db:migrate
実行が成功すると、以下のようなテーブル定義になっていることが確認できます ( MySQL にて)。
mysql> show create table Comments;
+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Table | Create Table |
+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Comments | CREATE TABLE `Comments` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`content` text,
`createdAt` datetime NOT NULL,
`updatedAt` datetime NOT NULL,
`user_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `fk_comments_users` (`user_id`),
CONSTRAINT `fk_comments_users` FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8 |
+----------+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
1 row in set (0.00 sec)
CASCADE 制約によって、 User を 削除した時に、紐付く Comment も削除されるようになります。
動かなかった方法
マニュアル や チュートリアル 、 Stack Overflow などによると、 model にて、 hasMany メソッドに次のように onDelete オプションと hooks オプションを与えれば cascade 削除が動くようなのですが、動作しませんでした。
Users.hasMany(Comments, { onDelete: 'cascade', hooks: true });
より、具体的な記述は次の通りです。
'use strict';
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
name: DataTypes.STRING,
age: DataTypes.INTEGER
}, {});
User.associate = function(models) {
// associations can be defined here
User.hasMany(models.Comment, {
foreignKey: 'user_id',
onDelete: 'cascade',
hooks: true
});
};
return User;
}
何か知見をお持ちの方があれば、ご教示いただけるとありがたいです。