使用 SequelizeJS 编写带有外键的迁移

Writing Migrations with Foreign Keys Using SequelizeJS

背景

我正在使用 SequelizeJS 构建一个项目,这是一个流行的 NodeJS ORM。在设计模式时,似乎有两种策略:

  1. 创建模型代码并使用 .sync() 函数自动为您的模型生成表。
  2. 创建模型代码并写入manual migrations using QueryInterface and umzug

我的理解是#1 更适合快速原型制作,但#2 是预期随着时间的推移而发展的项目以及生产数据需要能够在迁移中生存的项目的最佳实践。

这个问题属于策略#2。

问题

我的表具有必须通过外键反映的关系。

How do I create tables with foreign key relationships with one another through the Sequelize QueryInterface?

.createTable() 方法接收列字典。您可以在 documentation for .define() 中查看有效属性列表,特别是通过查看参数 table.

中的 [attributes.column.*]

要创建具有外键关系的属性,请使用“references”和“referencesKey”字段:

例如,以下将创建一个 users table 和一个 user_emails table 来引用用户 table.

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' }
    }
  })
});

What columns and helper tables are required by sequelize? For example, it appears that specific columns such as createdAt or updatedAt are expected.

标准模型似乎需要每个 table、updatedAtcreatedAt 列。

queryInterface.createTable('users', {
  id: {
    type: Sequelize.INTEGER,
    primaryKey: true,
    autoIncrement: true
  },
  createdAt: {
    type: Sequelize.DATE
  },
  updatedAt: {
    type: Sequelize.DATE
  }
}

如果您在模型上设置 paranoid to true,您还需要一个 deletedAt 时间戳。

我想提供另一种更多手动选择,因为在使用手动迁移和查询接口时,我运行遇到以下问题:我在迁移文件夹中有 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',
}))

所以第一个是下面的解决方案,第二个问题:你不需要明确提到 createdAtupdatedAt 因为它们是由 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'

  })
)

这是创建用于添加列的迁移文件。

这里我想在userstable中添加一列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'),
        ]);
      }
    };

在用户 table 中,我将创建一个名为 region_id 的列以及类型和 relation/foreign key/references。就是这样。