在本教程中,你将学习 Sequelize 中的模型以及如何使用它们.
模型是 Sequelize 的本质. 模型是代表数据库中表的抽象. 在 Sequelize 中,它是一个 Model 的扩展类.
该模型告诉 Sequelize 有关它代表的实体的几件事,例如数据库中表的名称以及它具有的列(及其数据类型).
Sequelize 中的模型有一个名称. 此名称不必与它在数据库中表示的表的名称相同. 通常,模型具有单数名称(例如,User
),而表具有复数名称(例如, Users
),当然这是完全可配置的.
模型定义#
在 Sequelize 中可以用两种等效的方式定义模型:
定义模型后,可通过其模型名称在 sequelize.models
中使用该模型.
为了学习一个示例,我们将考虑创建一个代表用户的模型,该模型具有一个 firstName
和一个 lastName
. 我们希望将模型称为 User
,并将其表示的表在数据库中称为 Users
.
定义该模型的两种方法如下所示. 定义后,我们可以使用 sequelize.models.User
访问模型.
const { Sequelize, DataTypes } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory:');
const User = sequelize.define('User', {
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
}
}, {
});
console.log(User === sequelize.models.User);
const { Sequelize, DataTypes, Model } = require('sequelize');
const sequelize = new Sequelize('sqlite::memory');
class User extends Model {}
User.init({
firstName: {
type: DataTypes.STRING,
allowNull: false
},
lastName: {
type: DataTypes.STRING
}
}, {
sequelize,
modelName: 'User'
});
console.log(User === sequelize.models.User);
在内部,sequelize.define
调用 Model.init
,因此两种方法本质上是等效的.
表名推断#
请注意,在以上两种方法中,都从未明确定义表名(Users
). 但是,给出了模型名称(User
).
默认情况下,当未提供表名时,Sequelize 会自动将模型名复数并将其用作表名. 这种复数是通过称为 inflection 的库在后台完成的,因此可以正确计算不规则的复数(例如 person -> people
).
当然,此行为很容易配置.
强制表名称等于模型名称#
你可以使用 freezeTableName: true
参数停止 Sequelize 执行自动复数化. 这样,Sequelize 将推断表名称等于模型名称,而无需进行任何修改:
sequelize.define('User', {
}, {
freezeTableName: true
});
上面的示例将创建一个名为 User
的模型,该模型指向一个也名为 User
的表.
也可以为 sequelize 实例全局定义此行为:
const sequelize = new Sequelize('sqlite::memory:', {
define: {
freezeTableName: true
}
});
这样,所有表将使用与模型名称相同的名称.
直接提供表名#
你也可以直接直接告诉 Sequelize 表名称:
sequelize.define('User', {
}, {
tableName: 'Employees'
});
模型同步#
定义模型时,你要告诉 Sequelize 有关数据库中表的一些信息. 但是,如果该表实际上不存在于数据库中怎么办? 如果存在,但具有不同的列,较少的列或任何其他差异,该怎么办?
这就是模型同步的来源.可以通过调用一个异步函数(返回一个Promise)model.sync(options)
. 通过此调用,Sequelize 将自动对数据库执行 SQL 查询. 请注意,这仅更改数据库中的表,而不更改 JavaScript 端的模型.
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("所有模型均已成功同步.");
删除表#
删除与模型相关的表:
await User.drop();
console.log("用户表已删除!");
删除所有表:
await sequelize.drop();
console.log("所有表已删除!");
数据库安全检查#
如上所示,sync
和drop
操作是破坏性的. Sequelize 使用 match
参数作为附加的安全检查,该检查将接受 RegExp:
sequelize.sync({ force: true, match: /_test$/ });
生产环境同步#
如上所示,sync({ force: true })
和 sync({ alter: true })
可能是破坏性操作. 因此,不建议将它们用于生产级软件中. 相反,应该在 Sequelize CLI 的帮助下使用高级概念 Migrations(迁移) 进行同步.
时间戳#
默认情况下,Sequelize 使用数据类型 DataTypes.DATE
自动向每个模型添加 createdAt
和 updatedAt
字段. 这些字段会自动进行管理 - 每当你使用Sequelize 创建或更新内容时,这些字段都会被自动设置. createdAt
字段将包含代表创建时刻的时间戳,而 updatedAt
字段将包含最新更新的时间戳.
注意: 这是在 Sequelize 级别完成的(即未使用 SQL触发器 完成). 这意味着直接 SQL 查询(例如,通过任何其他方式在不使用 Sequelize 的情况下执行的查询)将不会导致这些字段自动更新.
对于带有 timestamps: false
参数的模型,可以禁用此行为:
sequelize.define('User', {
}, {
timestamps: false
});
也可以只启用 createdAt
/updatedAt
之一,并为这些列提供自定义名称:
class Foo extends Model {}
Foo.init({ }, {
sequelize,
timestamps: true,
createdAt: false,
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"
}
});
一些特殊的值,例如 Sequelize.NOW
,也能被接受:
sequelize.define('Foo', {
bar: {
type: DataTypes.DATETIME,
defaultValue: Sequelize.NOW
}
});
数据类型#
你在模型中定义的每一列都必须具有数据类型. Sequelize 提供很多内置数据类型. 要访问内置数据类型,必须导入 DataTypes
:
const { DataTypes } = require("sequelize");
字符串#
DataTypes.STRING
DataTypes.STRING(1234)
DataTypes.STRING.BINARY
DataTypes.TEXT
DataTypes.TEXT('tiny')
DataTypes.CITEXT
DataTypes.INTEGER
DataTypes.BIGINT
DataTypes.BIGINT(11)
DataTypes.FLOAT
DataTypes.FLOAT(11)
DataTypes.FLOAT(11, 10)
DataTypes.REAL
DataTypes.REAL(11)
DataTypes.REAL(11, 12)
DataTypes.DOUBLE
DataTypes.DOUBLE(11)
DataTypes.DOUBLE(11, 10)
DataTypes.DECIMAL
DataTypes.DECIMAL(10, 2)
无符号和零填充整数 - 仅限于MySQL/MariaDB#
在 MySQL 和 MariaDB 中,可以将数据类型INTEGER
, BIGINT
, FLOAT
和 DOUBLE
设置为无符号或零填充(或两者),如下所示:
DataTypes.INTEGER.UNSIGNED
DataTypes.INTEGER.ZEROFILL
DataTypes.INTEGER.UNSIGNED.ZEROFILL
DataTypes.DATE
DataTypes.DATE(6)
DataTypes.DATEONLY
UUID#
对于 UUID,使用 DataTypes.UUID
. 对于 PostgreSQL 和 SQLite,它会是 UUID
数据类型;对于 MySQL,它则变成CHAR(36)
. Sequelize 可以自动为这些字段生成 UUID,只需使用 Sequelize.UUIDV1
或 Sequelize.UUIDV4
作为默认值即可:
{
type: DataTypes.UUID,
defaultValue: Sequelize.UUIDV4
}
还有其他数据类型,请参见其它数据类型.
列参数#
在定义列时,除了指定列的 type
以及上面提到的 allowNull
和 defaultValue
参数外,还有很多可用的参数. 下面是一些示例.
const { Model, DataTypes, Deferrable } = require("sequelize");
class Foo extends Model {}
Foo.init({
flag: { type: DataTypes.BOOLEAN, allowNull: false, defaultValue: true },
myDate: { type: DataTypes.DATE, defaultValue: DataTypes.NOW },
title: { type: DataTypes.STRING, allowNull: false },
uniqueOne: { type: DataTypes.STRING, unique: 'compositeIndex' },
uniqueTwo: { type: DataTypes.INTEGER, unique: 'compositeIndex' },
someUnique: { type: DataTypes.STRING, unique: true },
identifier: { type: DataTypes.STRING, primaryKey: true },
incrementMe: { type: DataTypes.INTEGER, autoIncrement: true },
fieldWithUnderscores: { type: DataTypes.STRING, field: 'field_with_underscores' },
bar_id: {
type: DataTypes.INTEGER,
references: {
model: Bar,
key: 'id',
deferrable: Deferrable.INITIALLY_IMMEDIATE
}
},
commentMe: {
type: DataTypes.INTEGER,
comment: '这是带有注释的列'
}
}, {
sequelize,
modelName: 'foo',
indexes: [{ unique: true, fields: ['someUnique'] }]
});
利用模型作为类#
Sequelize 模型是 ES6 类. 你可以非常轻松地添加自定义实例或类级别的方法.
class User extends Model {
static classLevelMethod() {
return 'foo';
}
instanceLevelMethod() {
return 'bar';
}
getFullname() {
return [this.firstname, this.lastname].join(' ');
}
}
User.init({
firstname: Sequelize.TEXT,
lastname: Sequelize.TEXT
}, { sequelize });
console.log(User.classLevelMethod());
const user = User.build({ firstname: 'Jane', lastname: 'Doe' });
console.log(user.instanceLevelMethod());
console.log(user.getFullname());