sequelize 模型、迁移文件和外键。哪一个是对的?
Posted
技术标签:
【中文标题】sequelize 模型、迁移文件和外键。哪一个是对的?【英文标题】:sequelize model, migration file and foreign key. which one is right? 【发布时间】:2018-11-08 03:04:46 【问题描述】:第一次开始学习sequelize的时候,我只是不知道,只是复制粘贴代码来建立两个模型之间的关系。
我是否必须将外键同时插入模型文件和迁移文件或仅用于迁移文件,这让我很困惑。
我知道迁移是具有更改数据库命令的文件。
所以我们必须手动将外键插入迁移文件,以便数据库可以创建它们。
在sequelize doc中,如果我们添加了has many和before的关系,sequelize会自动添加外键。
所以我真的很困惑是否必须添加它们。
我在得到 550 个答案之前提出的一些问题。
有人说我们不必手动将外键添加到模型中,因为 sequelize 会自动添加它们。
但有人说我们必须手动将外键添加到模型中,因为我们必须匹配(同步)模型和迁移文件之间的列。
更糟糕的是,解释sequelize关系的文章各不相同。
那么,哪个是正确的??
我真的很想得到明确的答案。
能得到一些理由真是太感谢了(如果我们必须给模型添加外键)
不夸张,我对这个问题已经好奇了大约六个月了。
【问题讨论】:
【参考方案1】:在创建迁移时,您还应该编写外键。也写在模型中,这样就很容易处理查询。 我们可以通过例子看到它。考虑它们是两个表 Item 和 Item_Types
1 Item_type 有很多 Items 所以,
Item_type 的迁移文件 (migration_create_item_type.js)
'use strict';
module.exports =
up: function (queryInterface, Sequelize)
return queryInterface.createTable('item_types',
id:
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
,
item_type:
type: Sequelize.STRING
,
type_desc:
type: Sequelize.STRING
,
createdAt:
allowNull: true,
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
,
updatedAt:
allowNull: true,
type: Sequelize.DATE,
defaultValue: Sequelize.NOW
);
,
down: function (queryInterface, Sequelize)
return queryInterface.dropTable('item_types');
;
项目的迁移文件 (migration_create_item.js)
'use strict';
module.exports =
up: function (queryInterface, Sequelize)
return queryInterface.createTable('items',
id:
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
,
item_name:
type: Sequelize.STRING
,
item_desc:
type: Sequelize.STRING
,
item_type_id:
type: Sequelize.INTEGER,
references:
model: 'item_types',
key: 'id'
,
createdAt:
allowNull: false,
type: Sequelize.DATE
,
updatedAt:
allowNull: false,
type: Sequelize.DATE
);
,
down: function (queryInterface, Sequelize)
return queryInterface.dropTable('items');
;
请注意,始终先创建父表,然后再创建其他表,即创建所有没有外键的表,然后再创建其他表
模型文件 Item_type (item_type.js)
'use strict';
module.exports = function (sequelize, DataTypes)
var item_type = sequelize.define('item_type',
item_type: DataTypes.STRING,
type_desc: DataTypes.STRING
);
item_type.associate = function (models)
item_type.hasMany(models.item, foreignKey: 'item_type_id');
;
return item_type;
;
模型文件项目(item.js)
'use strict';
var Logger = require('./../utils/logger');
var log = new Logger('item_type_factory');
module.exports = function (sequelize, DataTypes)
var item = sequelize.define('item',
item_name: DataTypes.STRING,
item_desc: DataTypes.STRING
);
item.associate = function (models)
item.item_type = item.belongsTo(models.item_type, foreignKey: 'id', target_key: 'item_type_id');
item.order_details = item.hasMany(models.order_details);
item.user = item.belongsToMany(models.user, through: 'supplier_items')
;
item.addNewItem = function (data)
return item.create(data, include: [association: item.item_type]);
;
item.findAndCreate = function (data, item_name)
return new Promise(function (resolve, reject)
item.findOrCreate(
where: 'item_name': item_name, defaults: data
).spread(function (record_data, created)
resolve(record_data);
).catch(function (insert_error)
reject(insert_error);
);
);
;
item.findAllItems = function ()
return item.findAll(
include: [association: item.item_type]
);
;
return item;
;
有关 sequlize 的基础知识,您可以参考以下文章, Getting started with Sequelize 仅供参考。
【讨论】:
这真的很棒。感谢您对代码的详细解释。我还想知道的一件事是,根据答案,***.com/questions/50386288/… 即使我们不添加任何外键,数据库也会创建外键列。 (同步的情况) 所以如果我们不向模型添加外键,就没有办法访问它们.. 对吧? 是的,你是对的。迁移和模型是两个不同的东西,迁移可能是为了改变表,插入默认值。这应该与模型无关。根据定义,模型是数据库表的更新版本。!! 是的,如果我们不添加外键我们无法通过orm编写正确的查询。 基本上在使用迁移时,数据库包含 1 个附加表“SequelizeMeta”,其中包含正确执行的迁移名称。您还可以使用迁移查询降级迁移【参考方案2】:我们应该如何创建数据库架构
我们在这里有两个选择。使用sync
进行迁移或续集。总是更喜欢迁移而不是sync
。迁移功能更强大,您可以使用它撤消、重做等等。 sync
不反映表格更改。例如,您定义了某个模型说User
,却忘记添加gender
。现在,如果您想使用 Sequelize 添加此列,则必须使用 force:true
,这将删除您的所有 User
数据,这在生产中是不可取的。
谁应该定义外键约束
根据软件设计原则,无论应用程序逻辑 (Sequelize) 是否实现相同的逻辑,您的数据库约束和验证都应始终到位。例如,新开发人员可以编写原始查询,如果您没有正确的约束条件,可能会弄乱您的整个数据库。
但是,我们还想使用 sequelize 对所有关联进行正确的查询。如果 sequelize 知道数据库中存在哪些关联以及应该是什么外键,那么 sequelize 可以做到这一点的唯一方法。
因此,应在迁移和续集级别定义外键约束。
数据库约束示例
如上图所示,约束是在我的数据库架构上定义的。
sequelize 约束示例
module.exports = (sequelize, DataTypes) =>
const Designation = sequelize.define('designation',
doctorId:
type: DataTypes.STRING,
allowNull: false,
field: 'doctor_id',
,
name:
type: DataTypes.STRING,
allowNull: false,
,
, );
Designation.associate = (models) =>
models.designation.belongsTo(models.doctor,
onDelete: 'cascade',
);
;
【讨论】:
感谢您的回答。因此向模型添加外键的目的是用非查询(js 语法)控制数据库。我理解正确吗? ***.com/questions/50386288/… 根据这篇文章,如果我使用同步和外键列会自动创建到数据库,即使我没有将外键添加到模型中。但是即使我们使用sync,还是建议在模型中添加外键,因为我们必须控制db,对吧? 如果以上这两个问题是正确的,我的困惑将完全消除。谢谢! @AbhinavD 对第一条评论:是的。 Sequelize 是一个 ORM,我们可以使用它的所有功能,以便我们的查询变得更容易,并且 sequelize 还带来了许多其他好处。对于评论 2:如果您已定义关联,sequelize 将尝试假定外键名称并使用它来进行关联。 现在我解决了我的好奇心。因此,无论是使用同步还是迁移,将外键插入模型只是一种选择。但是如果我们想用 orm 查询,我们必须这样做。所以可能需要可选的东西。非常感谢。以上是关于sequelize 模型、迁移文件和外键。哪一个是对的?的主要内容,如果未能解决你的问题,请参考以下文章