Написание миграции с использованием внешних ключей с использованием SequelizeJS
Фон
Я строю проект с SequelizeJS, популярной ORM для NodeJS. При разработке схемы, кажется, есть две тактики:
- Создайте код модели и используйте функцию.sync() для автоматического создания таблиц для ваших моделей.
- Создайте код модели и напишите миграции вручную, используя QueryInterface и umzug.
Насколько я понимаю, # 1 лучше для быстрого создания прототипов, но что # 2 - это лучшая практика для проектов, которые, как ожидается, будут развиваться со временем и где производственные данные должны быть в состоянии пережить миграции.
Этот вопрос относится к тактике № 2.
Вопросы)
Мои таблицы имеют отношения, которые должны быть отражены через внешние ключи.
-
Как мне создать таблицы с отношениями внешнего ключа друг с другом через Sequelize QueryInterface?
-
Какие столбцы и вспомогательные таблицы требуются Sequelize? Например, кажется, что ожидаются определенные столбцы, такие как созданный или обновленный.
Ответы
Ответ 1
Как мне создать таблицы с отношениями внешнего ключа друг с другом через Sequelize QueryInterface?
Метод .createTable()
принимает словарь столбцов. Вы можете увидеть список допустимых атрибутов в документации для .define()
, в частности, посмотрев строки [attributes.column.*]
В таблице параметров.
Чтобы создать атрибут с отношением внешнего ключа, используйте поля "ссылки" и "ссылки":
Например, следующее создаст таблицу 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? Например, кажется, что ожидаются определенные столбцы, такие как созданный или обновленный.
Похоже, что стандартная модель будет ожидать updatedAt
id
, updatedAt
и createdAt
для каждой таблицы.
queryInterface.createTable('users', {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
createdAt: {
type: Sequelize.DATE
},
updatedAt: {
type: Sequelize.DATE
}
}
Если для вашей модели вы установили для paranoid
значение true
, вам также понадобится deletedAt
метку времени deletedAt
.
Ответ 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',
}))