sequelize-cli使用经验总结

Sequelize 是一个基于 promise 的 Node.js ORM, 目前支持 Postgres, MySQL, SQLite 和 Microsoft SQL Server. 它具有强大的事务支持, 关联关系, 读取和复制等功能[2]. 下面主要介绍如何使用sequelize-cli工具快速构建nodejs的数据访问层。

基于express创建nodejs web应用

基于express建立nodejs的web应用,在此基础上再使用sequlize建立数据访问层和数据库。

1
2
3
4
mkdir myapp
cd myapp
express
npm install

基于sequelize创建数据访问层和数据库

安装sequlize

1
2
npm install --save sequelize
npm install --save mysql2

安装sequelize-cli

首先应安装sequelize-cli工具,可以选择全局安装,也可以选择本地安装。

1
2
npm install --save-dev sequelize-cli
npm install -g sequelize-cli

建立初始的ORM引导框架

使用如下命令在Nodejs Web应用中建立初始的数据访问层。

1
2
3
mkdir db
cd db
../node_modules/.bin/sequelize init

这将创建以下文件夹:

  • config, 包含配置文件,它告诉CLI如何连接数据库
  • models,包含您的项目的所有模型
  • migrations, 包含所有迁移文件
  • seeders, 包含所有种子文件

修改配置文件以连接到数据库管理系统,并创建数据库

在建立模型之前,应先修改config/config.json,以告诉 CLI 如何连接到数据库。config/config.json内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
{
"development": {
"username": "root",
"password": "root",
"database": "database_development",
"host": "127.0.0.1",
"dialect": "mysql",
"pool":{
"max": 5,
"min": 0,
"idle": 10000
},
"timezone": "+08:00",
"define":{
"charset": "utf8",
"dialectOptions":{
"collate": "utf8_general_ci"
}
}
},
"test": {
"username": "root",
"password": "root",
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql"
},
"production": {
"username": "root",
"password": "root",
"database": "database_test",
"host": "127.0.0.1",
"dialect": "mysql",
"pool":{
"max": 5,
"min": 0,
"idle": 10000
},
"timezone": "+08:00",
"define":{
"charset": "utf8",
"dialectOptions":{
"collate": "utf8_general_ci"
}
}
}
}

上述配置修改了数据库的字符集,使之能支持中文。当然在创建数据库之前,应配置mysql数据库管理系,使其支持utf8字符集。可执行如下命令查看其支持的字符集,如果其不支持uft字符集,请按照参考链接[3]进行修改。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
mysql> show variables like '%char%';
+--------------------------+---------------------------------------------------------+
| Variable_name | Value |
+--------------------------+---------------------------------------------------------+
| character_set_client | utf8 |
| character_set_connection | utf8 |
| character_set_database | utf8 |
| character_set_filesystem | binary |
| character_set_results | utf8 |
| character_set_server | utf8 |
| character_set_system | utf8 |
| character_sets_dir | C:\Program Files\MySQL\MySQL Server 5.5\share\charsets\ |
+--------------------------+---------------------------------------------------------+
8 rows in set (0.00 sec)

使用如下命令创建数据库:

1
../node_modules/.bin/sequelize db:create

使用如下命令删除数据库:

1
../node_modules/.bin/sequelize db:drop

创建模型

我们将使用 model:generate 命令。 此命令需要两个选项:

  • name, 模型的名称
  • attributes, 模型的属性列表

创建一个名叫 User 的模型:

1
../node_modules/.bin/sequelize model:generate --name User --attributes firstName:string,lastName:string,email:string

这将发生以下事情:

  • 在 models 文件夹中创建了一个 user 模型文件
  • 在 migrations 文件夹中创建了一个名字像 XXXXXXXXXXXXXX-create-user.js 的迁移文件

注意: _Sequelize 将只使用模型文件,它是表描述。另一边,迁移文件是该模型的更改,或更具体的是说 CLI 所使用的表。 处理迁移,如提交或日志,以进行数据库的某些更改。

再创建一个名为Role的模型,它跟User是一对多的关系:

1
../node_modules/.bin/sequelize model:generate --name Role --attributes roleName:string

定义关系

Role和User是一对多的关系,因此需要修改它们的模型定义。
修改models/role.js如下:

1
2
3
4
5
6
7
8
9
10
11
'use strict';
module.exports = (sequelize, DataTypes) => {
var Role = sequelize.define('Role', {
roleName: DataTypes.STRING
}, {});
Role.associate = function(models) {
// associations can be defined here
Role.hasMany(models.User)
};
return Role;
};

修改models/user.js如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'use strict';
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('User', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: DataTypes.STRING
}, {});
User.associate = function(models) {
// associations can be defined here
User.belongsTo(models.Role, {
onDelete: "NULL",
foreignKey: {
allowNull: false
}
})
};
return User;
};

修改和运行迁移

Role和User是一对多的关系,因此需要修改User迁移文件的定义。
修改migrates/20180622153152-create-user.js如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
'use strict';
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('Users', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
roleId: { // name of the key we're adding
type: Sequelize.INTEGER,
allowNull: false,
references: {
model: 'Roles', // name of Target model
key: 'id', // key in Target model that we're referencing
},
onUpdate: 'CASCADE',
onDelete: 'CASCADE',
},
firstName: {
type: Sequelize.STRING
},
lastName: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
createdAt: {
allowNull: false,
type: Sequelize.DATE
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE
}
});
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('Users');
}
};

注意:这里主要给User添加了外键字段,外键字段命名有规则:通常为小写的模型名加Id,即驼峰风格。例如这里加了roleId的外键字段。

直到目前为止,CLI没有将任何东西插入数据库。 刚刚为模型 User和Role创建了必需的模型和迁移文件。 现在要在数据库中实际创建该表,需要运行 db:migrate 命令。

1
../node_modules/.bin/sequelize db:migrate

此命令将执行这些步骤:

  • 将在数据库中创建一个名为 SequelizeMeta 的表。 此表用于记录在当前数据库上运行的迁移
  • 开始寻找尚未运行的任何迁移文件。 这可以通过检查 SequelizeMeta 表。 在这个例子中,它将运行创建的 XXXXXXXXXXXXXX-create-role.js和XXXXXXXXXXXXXX-create-user.js 迁移。
  • 创建一个名为 Roles 的表,其中包含其迁移文件中指定的所有列。
  • 创建一个名为 Users 的表,其中包含其迁移文件中指定的所有列。

除了使用sequelize db:migrate命令创建数据库表之外,可以使用models同步创建或删除数据库表,例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
if (appConfig.dbCreated === false) {
models.sequelize.sync().then(function() {
//保存应用配置
appConfig.dbCreated = true;
fs.writeFile(__dirname + '/../config/appConfig.json', JSON.stringify(appConfig), function(err) {
if (err) return console.error(err);
console.log('app config save is done');
});
Promise.all([
models.T_Role.create({ID:pwdHash.createMd5(Math.random().toString()),Role_Name:'管理员'}),
models.T_User.create({ID:pwdHash.createMd5(Math.random().toString()),Account:appConfig.adminAccount,Password:pwdHash.createHash(appConfig.adminPassword),Audit:true,Avatar:'/avatar/default.jpg'}),
models.T_Role.create({ID:pwdHash.createMd5(Math.random().toString()),Role_Name:'普通用户'})

]).then(function (result){
//console.log(result);
var role1=result[0];
var user1=result[1];
role1.setT_Users(user1).catch(err=>console.log(err));
}).catch(err=>console.log(err));


server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
});
} else {
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
}

创建种子,生成测试数据

假设我们希望在默认情况下将一些数据插入到几个表中。 例如创建几个用户和角色:

1
2
../node_modules/.bin/sequelize seed:generate --name demo-role
../node_modules/.bin/sequelize seed:generate --name demo-user

这个命令将会在 seeders 文件夹中创建两个种子文件。文件名看起来像是 XXXXXXXXXXXXXX-demo-role.js和XXXXXXXXXXXXXX-demo-user.js,它遵循相同的 up/down 语义,如迁移文件。

现在我们应该编辑这两个文件,将演示角色插入Role表,将演示用户插入User表。修改XXXXXXXXXXXXXX-demo-role.js如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
'use strict';

module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('Roles', [{
roleName: '管理员',
createdAt:new Date(),
updatedAt:new Date()
},{
roleName: '普通用户',
createdAt:new Date(),
updatedAt:new Date()
}], {});

},

down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('Roles', null, {});

}
};

修改XXXXXXXXXXXXXX-demo-user.js如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
'use strict';

module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.bulkInsert('Users', [{
roleId:1,
firstName: 'John',
lastName: 'Doe',
email: 'demo@demo.com',
createdAt:new Date(),
updatedAt:new Date()
},{
roleId:1,
firstName: 'Jack',
lastName: 'Smith',
email: 'jack@demo.com',
createdAt:new Date(),
updatedAt:new Date()
}], {});

},

down: (queryInterface, Sequelize) => {
return queryInterface.bulkDelete('Users', null, {});
}
};

种子文件修改后,即可使用如下命令将演示数据插入数据库中:

1
../node_modules/.bin/sequelize db:seed:all

工程实践经验总结

在工程实践中,只需使用sequelize-cli创建数据库,生成models即可,然后使用代码直接根据models创建数据库表,并生成测试数据。

参考链接

  1. Sequelize Reference,by sequelizejs.
  2. Sequelize 中文文档,by demopark.
  3. 解决Mysql中文乱码问题, by 最怕认真.
  4. How to set primary key type to UUID via Sequelize CLI,by stackoverflow.
  5. 数据库表主键设计方法,by jackhuang.
  6. Variable,by sequelize.
  7. cascade delete does not work,by sequelize.
  8. Adding foreign key to a table using Sequelize,by Nathan Sebhastian.
  9. Eager Loading - 预先加载,by demopark.