使用 SequelizeJS 编写带有外键的迁移
Posted
技术标签:
【中文标题】使用 SequelizeJS 编写带有外键的迁移【英文标题】:Writing Migrations with Foreign Keys Using SequelizeJS 【发布时间】:2015-07-06 10:46:37 【问题描述】:背景
我正在使用SequelizeJS 构建一个项目,这是一种流行的 NodeJS ORM。在设计模式时,似乎有两种策略:
-
创建模型代码并使用 .sync() 函数为您的模型自动生成表。
创建模型代码并使用QueryInterface 和umzug 编写manual migrations。
我的理解是,#1 更适合快速原型制作,但#2 是预计随着时间推移而发展的项目以及生产数据需要能够在迁移中幸存下来的项目的最佳实践。
这个问题与策略 #2 相关。
问题
我的表具有必须通过外键反映的关系。
如何通过 Sequelize QueryInterface 创建具有外键关系的表?
Sequelize 需要哪些列和辅助表?例如,似乎需要特定列,例如 createdAt 或 updatedAt。
【问题讨论】:
【参考方案1】:如何通过 Sequelize QueryInterface 创建具有外键关系的表?
.createTable()
方法接收一个列字典。您可以查看documentation for .define()
中的有效属性列表,特别是通过查看params 表中的[attributes.column.*]
行。
要创建具有外键关系的属性,请使用“references”和“referencesKey”字段:
例如,下面将创建一个users
表和一个引用用户表的user_emails
表。
queryInterface.createTable('users',
id:
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
).then(function()
queryInterface.createTable('user_emails',
userId:
type: Sequelize.INTEGER,
references: model: 'users', key: 'id'
)
);
sequelize 需要哪些列和辅助表?例如,似乎需要特定列,例如 createdAt 或 updatedAt。
标准模型似乎需要为每个表提供id
、updatedAt
和createdAt
列。
queryInterface.createTable('users',
id:
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
,
createdAt:
type: Sequelize.DATE
,
updatedAt:
type: Sequelize.DATE
如果您在模型上设置了paranoid
to true
,您还需要一个deletedAt
时间戳。
【讨论】:
对于在这里结束的人,这个答案很好,但现在不推荐使用语法,请使用以下内容:references: model: 'users', key: 'id' 你也应该删除 referencesKey: 'id' ;) (herp derp,这就是我在假期使用 *** 得到的) 如何定义对多个实体的引用?因此,如果我想让“users”表有一个引用“user_emails”中多行的列(而不是当前示例,“user_emails”行引用“users”中的一行)。 @slifty 感谢您的详细回答。它帮助很大。【参考方案2】:我想提供另一个更多手动选择,因为在使用手动迁移和 queryInterface 时,我遇到了以下问题:迁移文件夹中有 2 个文件,就像这样
migrations/create-project.js
migrations/create-projectType.js
因为project
有列projectTypeId
它引用了projectType
,由于文件的顺序尚未创建,这导致了错误。
我通过在创建两个表后添加外键约束来解决它。就我而言,我决定把它写在create-projectType.js
:
queryInterface.createTable('project_type',
// table attributes ...
)
.then(() => queryInterface.addConstraint('project', ['projectTypeId'],
type: 'FOREIGN KEY',
name: 'FK_projectType_project', // useful if using queryInterface.removeConstraint
references:
table: 'project_type',
field: 'id',
,
onDelete: 'no action',
onUpdate: 'no action',
))
【讨论】:
不错!请注意——您可能需要考虑使用开始文件名的顺序来命名您的迁移,以确保无论表名如何(例如01-create-projecttype.js
、02-create-project.js
)都以所需的顺序处理它们。这也很重要,因为当您编辑/添加表格时,您可以保持旧的迁移步骤完好无损(例如03-edit-projecttype.js
)。
@slifty 谢谢你——我真的开始这样做了!希望 cli 的 v4 支持多个迁移文件夹
它有帮助!我犯了一个愚蠢的错误,我在主键列和外键列中定义了不同的类型,因此我遭受了几分钟的痛苦。终于成功了:)【参考方案3】:
所以第一个问题是下面的解决方案和第二个问题:你不需要明确提及createdAt
和updatedAt
,因为它们是由 Sequelize 为你生成的。
解决办法是:
queryInterface.createTable('Images',
//...
).then(
return queryInterface.addConstraint('Images', ['postId'],
type: 'foreign key',
name: 'custom_fkey_images',
references: //Required field
table: 'Posts',
field: 'id'
,
onDelete: 'cascade',
onUpdate: 'cascade'
)
)
【讨论】:
嗨,OP 问了两个问题,你没有回答一个。请编辑您的答案并为您的解决方案添加一些描述。确保您正在回答 OP 的问题。【参考方案4】:这是为添加列创建迁移文件。
这里我想在 users 表中添加一列 area_id。运行命令:
sequelize migration:create --name add-area_id-in-users
一旦执行,就会在迁移文件夹中创建一个迁移文件 timestamp-add-region_id-in-users。
在创建的迁移文件中粘贴以下代码:
'use strict';
module.exports =
up: (queryInterface, Sequelize) =>
return Promise.all([
queryInterface.addColumn('users', 'region_id',
type: Sequelize.UUID,
references:
model: 'regions',
key: 'id',
,
onUpdate: 'CASCADE',
onDelete: 'SET NULL',
defaultValue: null, after: 'can_maintain_system'
),
]);
,
down: (queryInterface, Sequelize) =>
return Promise.all([
queryInterface.removeColumn('users', 'region_id'),
]);
;
在用户表中,我将创建一个名为 region_id 的列以及类型和关系/外键/引用。就是这样。
【讨论】:
以上是关于使用 SequelizeJS 编写带有外键的迁移的主要内容,如果未能解决你的问题,请参考以下文章