以下是本人在使用egg.js的ORM框架Sequelize时的一些经验,希望能给学习和使用egg.js并使用egg-Sequelize进行开发的小伙伴一些帮助,如果在阅读时有什么问题,欢迎和我联系。
1、数据表定义
以下为一个测试的数据库定义表:
module.exports = app => {
const { STRING, BIGINT, DATE, BOOLEAN, TEXT, INTEGER } = app.Sequelize;
const model = app.model.define('test', {
id: {
type: BIGINT(20),
primaryKey: true, // 主键
autoIncrement: true, // 自增
},
bigintData: {
type: BIGINT, // 默认是BIGINT(11)
comment: '我是BIGINT',
unique: true,
},
integerData: {
type: INTEGER, // 默认是INTEGER(11)
comment: '我是INTEGER',
},
stringData: {
type: STRING, // 默认是VARCHAR(255)
comment: '我是VARCHAR',
set(val) { // 在保存入数据库之前,对某字段进行处理
// 例如以下方法对保存入数据库之前的stringData字段进行大写处理
// 如存入时为test,那么经过处理并保存如数据库为TEST
this.setDataValue('stringData', val.toUpperCase());
}
},
textData: {
type: TEXT, // 默认是TEXT
comment: '我是TEXT',
},
dateData: {
type: DATE, // 默认是DATETIME
get() { // 在SELECT之后,对某字段进行处理
// 例如以下方法对查出的dateData进行字符串处理
// 如数据库中的值为'2020-10-29 18:00:00',取出之后就变为'时间为:2020-10-29 18:00:00'
return '时间为:' + this.getDataValue('dateData');
},
comment: '我是DATETIME',
},
booleanData: {
type: BOOLEAN, // 默认是TINYINT(1)
comment: '我是TINYINT(1)',
},
}, {
timestamps: false,
underscored: false,
freezeTableName: true,
tableName: 'tb_test', // 数据库表名为tb_test
charset: 'utf8',
collate: 'utf8_general_ci',
indexes: [
{
name: 'tb_test_string_data', // 索引名称
method: 'BTREE',
fields: [ 'stringData' ] // 索引列
}
]
});
return model;
};
2、数据结构同步到数据库
即只要在代码中写好数据结构然后调用某方法即能直接创建好数据库表;在简单数据表的创建和部署时,能够很好的避免因为写sql的错误导致数据库表创建失败导致的部署失败的问题;并且能够极大的加快工程初始化速度,之前既需要写sql也需要写代码中的数据结构Model,如今只需要写好数据表结构然后同步创建好数据库表,再将数据库表导出即能够得到数据库初始化脚本,方便了许多。
在工程初始化的地方,如app.js的serverDidReady钩子函数中,或者项目启动时的初始化定时任务中,调用
await ctx.model.sync();
即可,如果是上面的model所同步的数据表的SQL如下:
CREATE IF NOT EXISTS TABLE `tb_document_advise` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`docId` BIGINT(20) NULL DEFAULT NULL COMMENT 'docId',
`intNumber` INT(11) NULL DEFAULT NULL COMMENT 'intNumber',
`docVersion` VARCHAR(255) NULL DEFAULT NULL COMMENT 'docVersion',
`adviceContent` TEXT NULL DEFAULT NULL COMMENT 'adviceContent',
`submitTime` DATETIME NULL DEFAULT NULL COMMENT 'submitTime',
`isRead` TINYINT(1) NULL DEFAULT NULL COMMENT 'isRead',
PRIMARY KEY (`id`),
UNIQUE INDEX `docId` (`docId`),
INDEX `tb_document_advise_doc_version` (`docVersion`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
3、数据库事务操作
直接上代码
let transaction;
try {
// 建立事务对象
transaction = await this.ctx.model.transaction();
// 事务增操作
await this.ctx.model.test.create({ ... }, { transaction });
// 事务批量增操作
await this.ctx.model.test.bulkCreate([{ ... }], { transaction });
// 事务删操作
await this.ctx.model.test.destroy({
where: {
...
},
transaction,
});
// 事务改操作
await this.ctx.model.test.update({
...
}, {
where: {
...
},
transaction,
});
// 提交事务
await transaction.commit();
} catch (err) {
// 事务回滚
await transaction.rollback();
}
4、数据库中文排序
在开发办公IT系统时,经常需要用到中文排序,与传统排序不同中文排序在Sequelize上需要用别的方法进行实现:首先排序的字段要是索引,以上面的Model为例stringData字段是索引,那么可对该列进行中文排序:
const sequelize = this.ctx.model;
const datas = await this.ctx.model.test.findAll({
where: { ... },
order: [[ sequelize.literal('convert(stringData using gbk)') ]] // 中文ASC排序
// order: [[ sequelize.literal('convert(stringData using gbk)'), 'DESC' ]] // 中文DESC排序
});
5、关联查询
在开发过程中进程会遇到要使用联表查询的时候,那么如何来进行联表查询呢?
首先在需要进行联表查询的表中进行关联配置,以以上的Model为例
module.exports = app => {
const model = app.model.define('test', {
...
}, {
...
});
model.associate = function() {
// 关联test1表,外键为testId,即test1的testId参照test的id
// 假设test1表中还有字段data1
model.hasMany(app.model.Test1, {
as: 'test1Datas',
foreignKey: 'testId',
});
// 关联test2表,外键为testId,即test2的testId参照test的id
// 假设test2表中还有字段data2
model.hasMany(app.model.Test2, {
as: 'test2Datas',
foreignKey: 'testId',
});
};
return model;
};
对test1表进行关联查询
const result = await this.ctx.model.Test.findAll({
where: { ... },
include: [{
as: 'test1Data',
model: this.ctx.model.Test1,
required: false, // 如果为true则为内连接,这意味着,只有匹配到子模型的父模型才会被加载,默认为false左外连接;
// where: { ... }, // 若设置了搜索条件,则required为true
}]
})
若要对test1和test2同时关联则只需要在include中加入test2相关内容即可。
那么如果需要查询这样的情况:查询test记录并且同时关联test1和test2,当test1和test2中任意一个关联中有记录时test中的记录需要被查出,若均无记录则test记录不查出。对于这个问题使用include[i].where进行过滤明显就不行了,那么该如何进行问题的解决呢,我们将会使用到’$'来进行查询
const result = await this.ctx.model.Test.findAll({
where: {
[this.app.Sequelize.Op.or]: [
{ '$test1Data.test1$': 'xxx' },
{ '$test2Data.test2$': 'yyy' }
]
},
include: [{
as: 'test1Data',
model: this.ctx.model.Test1,
}, {
as: 'test2Data',
model: this.ctx.model.Test2,
}]
})
以上条件为,查找test1Data的test1为xxx或者test2Data.test2为yyy的test记录,这里 的 作 用 就 是 不 对 的作用就是不对 的作用就是不对…$两个美元符中的内容进行转义,在不使用美元符时将会在字段前加上该表的名字。
6、指定字段的枚举排序
当遇到某个字段如季节season字段需要排序时,可以使用以下排序
option.order = [
sequelize.fn('field', sequelize.col('season'), '夏天', '秋天', '春天', '冬天'),
];
以上就是以season的值按照夏天、秋天、春天、冬天进行排序。
如果对Sequelize的用法还需要更多的进行学习和了解的会,可以查看Sequelize的中文文档地址:https://itbilu.com/nodejs/npm/VkYIaRPz-.html