模型定义
在 Sequelize 中可以用两种等效的方式定义模型:
- 调用
sequelize.define(modelName, attributes, options)
- 扩展 Model 并调用
init(attributes, options)
定义模型后,可通过其模型名称在 sequelize.models
中使用该模型。
使用 sequelize.define
:
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('runoops_test', 'root', '123456', {
host: 'localhost',
dialect: 'mysql' /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
});
const User = sequelize.define('User', {
// 在这里定义模型属性
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull 默认为 true
}
}, {
// 这是其他模型参数
});
// `sequelize.define` 会返回模型
console.log(User === sequelize.models.User); // true
扩展 Model
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('runoops_test', 'root', '123456', {
host: 'localhost',
dialect: 'mysql' /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
});
class User extends Model {}
User.init({
// 在这里定义模型属性
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
// allowNull 默认为 true
}
}, {
// 这是其他模型参数
sequelize, // 我们需要传递连接实例
modelName: 'User' // 我们需要选择模型名称
});
// 定义的模型是类本身
console.log(User === sequelize.models.User); // true
在内部,sequelize.define
调用 Model.init
,因此两种方法本质上是等效的。
公共类字段的注意事项
添加与模型属性之一同名的公共类字段会出现问题. Sequelize 为通过 Model.init
定义的每个属性添加一个 getter 和一个 setter. 添加公共类字段将隐藏那些 getter 和 setter,从而阻止对模型的实际数据的访问。
// 无效的 class User extends Model { id; // 此字段将影响 sequelize 的 getter 和 setter. 它应该被删除. otherPublicField; // 这个字段不会影响任何东西. 没问题. } User.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true } }, { sequelize }); const user = new User({ id: 1 }); user.id; // undefined
// 有效的
class User extends Model {
otherPublicField;
}
User.init({
id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
}
}, { sequelize });
const user = new User({ id: 1 });
user.id; // 1
在 TypeScript 中, 您可以使用 declare
关键字添加键入信息, 而无需添加实际的公共类字段:
// 有效 class User extends Model { declare id: number; // 您可以使用 `declare` 关键字添加键入信息, 而无需添加实际的公共类字段. } User.init({ id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true } }, { sequelize }); const user = new User({ id: 1 }); user.id; // 1
表名推断
默认情况下,当未提供表名时,Sequelize 会自动将模型名复数并将其用作表名. 这种复数是通过称为 inflection 的库在后台完成的,因此可以正确计算不规则的复数(例如 person -> people
)。
强制表名称等于模型名称
sequelize.define('User', {
// ... (属性)
}, {
freezeTableName: true
});
上面的示例将创建一个名为 User
的模型,该模型指向一个也名为 User
的表.
也可以为 sequelize 实例全局定义此行为:
const sequelize = new Sequelize('runoops_test', 'root', '123456', {
host: 'localhost',
dialect: 'mysql' /* 选择 'mysql' | 'mariadb' | 'postgres' | 'mssql' 其一 */
freezeTableName: true
});
这样,所有表将使用与模型名称相同的名称。
直接提供表名
你也可以直接告诉 Sequelize 表名称:
sequelize.define('User', {
// ... (属性)
}, {
tableName: 'Employees'
});
模型同步
可以通过调用一个异步函数(返回一个Promise)model.sync(options)
来实现模型同步(执行SQL)。
User.sync() - 如果表不存在,则创建该表(如果已经存在,则不执行任何操作)
User.sync({ force: true }) - 将创建表,如果表已经存在,则将其首先删除
User.sync({ alter: true }) - 这将检查数据库中表的当前状态(它具有哪些列,它们的数据类型等),然后在表中进行必要的更改以使其与模型匹配.
实例
await User.sync({ force: true });
console.log("用户模型表刚刚(重新)创建!");
一次同步所有模型
你可以使用 sequelize.sync()
自动同步所有模型. 示例:
await sequelize.sync({ force: true });
console.log("所有模型均已成功同步.");
同步的数据表users 结构如下:
CREATE TABLE `users` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`firstName` varchar(255) NOT NULL,
`lastName` varchar(255) DEFAULT NULL,
`createdAt` datetime NOT NULL,
`updatedAt` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
删除表
删除与模型相关的表:
await User.drop(); console.log("用户表已删除!");
删除所有表:
await sequelize.drop();
console.log("所有表已删除!");
数据库安全检查
如上所示,sync
和drop
操作是破坏性的. Sequelize 使用 match
参数作为附加的安全检查,该检查将接受 RegExp:
// 仅当数据库名称以 '_test' 结尾时,它才会运行.sync() sequelize.sync({ force: true, match: /_test$/ });
时间戳
默认情况下,Sequelize 使用数据类型 DataTypes.DATE
自动向每个模型添加 createdAt
和 updatedAt
字段。
对于带有 timestamps: false
参数的模型,可以禁用此行为:
sequelize.define('User', {
// ... (属性)
}, {
timestamps: false
});
也可以只启用 createdAt
/updatedAt
之一,并为这些列提供自定义名称:
class Foo extends Model {} Foo.init({ /* 属性 */ }, { sequelize, // 不要忘记启用时间戳! timestamps: true, // 不想要 createdAt createdAt: false, // 想要 updatedAt 但是希望名称叫做 updateTimestamp updatedAt: 'updateTimestamp' });
列声明简写语法
如果关于列的唯一指定内容是其数据类型,则可以缩短语法:
// 例如: sequelize.define('User', { name: { type: DataTypes.STRING } }); // 可以简写为: sequelize.define('User', { name: DataTypes.STRING });
默认值
默认情况下,Sequelize 假定列的默认值为 NULL
. 可以通过将特定的 defaultValue
传递给列定义来更改此行为:
sequelize.define('User', { name: { type: DataTypes.STRING, defaultValue: "John Doe" } });
一些特殊的值,例如 DataTypes.NOW
,也能被接受:
sequelize.define('Foo', { bar: { type: DataTypes.DATETIME, defaultValue: DataTypes.NOW // 这样,当前日期/时间将用于填充此列(在插入时) } });
分享笔记