使用TS+Sequelize实现更简洁的CRUD

如果是经常使用Node来做服务端开发的童鞋,肯定不可避免的会操作数据库,做一些增删改查(CRUD,Create Read Update Delete)的操作,如果是一些简单的操作,类似定时脚本什么的,可能就直接生写SQL语句来实现功能了,而如果是在一些大型项目中,数十张、上百张的表,之间还会有一些(一对多,多对多)的映射关系,那么引入一个ORM(Object Relational Mapping)工具来帮助我们与数据库打交道就可以减轻一部分不必要的工作量,Sequelize就是其中比较受欢迎的一个。

CRUD原始版 手动拼接SQL

先来举例说明一下直接拼接SQL语句这样比较“底层”的操作方式:

CREATE TABLE animal ( id INT AUTO_INCREMENT, name VARCHAR(14) NOT NULL, weight INT NOT NULL, PRIMARY KEY (`id`) );

创建这样的一张表,三个字段,自增ID、name以及weight。
如果使用mysql这个包来直接操作数据库大概是这样的:

const connection = mysql.createConnection({}) const tableName = 'animal' connection.connect() // 我们假设已经支持了Promise // 查询 const [results] = await connection.query(` SELECT id, name, weight FROM ${tableName} `) // 新增 const name = 'Niko' const weight = 70 await connection.query(` INSERT INTO ${tableName} (name, weight) VALUES ('${name}', ${weight}) `) // 或者通过传入一个Object的方式也可以做到 await connection.query(`INSERT INTO ${tableName} SET ?`, { name, weight }) connection.end()

看起来也还算是比较清晰,但是这样带来的问题就是,开发人员需要对表结构足够的了解。
如果表中有十几个字段,对于开发人员来说这会是很大的记忆成本,你需要知道某个字段是什么类型,拼接SQL时还要注意插入时的顺序及类型,WHERE条件对应的查询参数类型,如果修改某个字段的类型,还要去处理对应的传参。
这样的项目尤其是在进行交接的时候更是一件恐怖的事情,新人又需要从头学习这些表结构。
以及还有一个问题,如果有哪天需要更换数据库了,放弃了MySQL,那么所有的SQL语句都要进行修改(因为各个数据库的方言可能有区别)

CRUD进阶版 Sequelize的使用

关于记忆这件事情,机器肯定会比人脑更靠谱儿,所以就有了ORM,这里就用到了在Node中比较流行的Sequelize。

ORM是干嘛的

首先可能需要解释下ORM是做什么使的,可以简单地理解为,使用面向对象的方式,通过操作对象来实现与数据库之前的交流,完成CRUD的动作。
开发者并不需要关心数据库的类型,也不需要关心实际的表结构,而是根据当前编程语言中对象的结构与数据库中表、字段进行映射。

就好比针对上边的animal表进行操作,不再需要在代码中去拼接SQL语句,而是直接调用类似Animal.create,Animal.find就可以完成对应的动作。

Sequelize的使用方式

首先我们要先下载Sequelize的依赖:

npm i sequelize npm i mysql2 # 以及对应的我们需要的数据库驱动

然后在程序中创建一个Sequelize的实例:

const Sequelize = require('Sequelize') const sequelize = new Sequelize('mysql://root:jarvis@127.0.0.1:3306/ts_test') // dialect://username:password@host:port/db_name // 针对上述的表,我们需要先建立对应的模型: const Animal = sequelize.define('animal', { id: { type: Sequelize.INTEGER, autoIncrement: true }, name: { type: Sequelize.STRING, allowNull: false }, weight: { type: Sequelize.INTEGER, allowNull: false }, }, { // 禁止sequelize修改表名,默认会在animal后边添加一个字母`s`表示负数 freezeTableName: true, // 禁止自动添加时间戳相关属性 timestamps: false, }) // 然后就可以开始使用咯 // 还是假设方法都已经支持了Promise // 查询 const results = await Animal.findAll({ raw: true, }) // 新增 const name = 'Niko' const weight = 70 await Animal.create({ name, weight, })

sequelize定义模型相关的各种配置:docs

抛开模型定义的部分,使用Sequelize无疑减轻了很多使用上的成本,因为模型的定义一般不太会去改变,一次定义多次使用,而使用手动拼接SQL的方式可能就需要将一段SQL改来改去的。

而且可以帮助进行字段类型的转换,避免出现类型强制转换出错NaN或者数字被截断等一些粗心导致的错误。

通过定义模型的方式来告诉程序,有哪些模型,模型的字段都是什么,让程序来帮助我们记忆,而非让我们自己去记忆。
我们只需要拿到对应的模型进行操作就好了。

这还不够

But,虽说切换为ORM工具已经帮助我们减少了很大一部分的记忆成本,但是依然还不够,我们仍然需要知道模型中都有哪些字段,才能在业务逻辑中进行使用,如果新人接手项目,仍然需要去翻看模型的定义才能知道有什么字段,所以就有了今天要说的真正的主角儿:sequelize-typescript

CRUD终极版 装饰器实现模型定义

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wsxddd.html