Typescript与orm框架sequelize语法冲突的问题

      如果不想在nodejs中大量的手写sql,就可以采用orm框架sequelize,它非常类似于Java的JPA,让你的代码看起来更规范简洁高效。不过在采用sequelize编写的过程中遇到了一些问题,而网上的资料又太少;不是没有去sequelize官网看过,主要是官网的API示例都是针对一般的js语法,而我的项目使用了TypeScript,有好多地方功能虽然可以正常执行,但是代码下面会冒红(红颜色波浪线),鼠标放上去提示:TS2322:the type xxx is not assign to xxxxx。这种属于语法问题,typescript要求的比较严格。

     下面来看一个例子,API为findOrCreate,意思是根据条件查找,如果找到就返回,没找到则创建一条。在对实体类进行jpa操作时,首先用sequelize定义字段类型与数据库字段的映射,例如:

export const StudentModel = sequelize.define('student', {
    id: {
        type: Sequelize.BIGINT,
        field: 'id',
        primaryKey: true,
        autoIncrement: true
    },
    name: {
        type: Sequelize.STRING,
        field: 'name'
    },
    age: {
        type: Sequelize.TINYINT,
        field: 'age'
    },
    tel: {
        type: Sequelize.STRING,
        field: 'tel'
    },
    createTime: {
        type: Sequelize.BIGINT,
        field: 'create_time'
    },
    updateTime: {
        type: Sequelize.BIGINT,
        field: 'update_time'
    }
}, {
    timestamps: false,
    tableName: 'student'
});

     按照官网 findOrCreate的用法,根据where条件后面的选项来查找记录,如果没找到,则将where里面的条件和defaults里面的属性一起作为待插入项,所以我只需要像如下这么写:

await StudentModel.findOrCreate(
    {
        where: {name: `${name}`, tel: `${tel}`},
        defaults: {
            age: `${age}`,
            createTime: `${time}`,
            updateTime: `${time}`}
    });

      事实是运行功能执行正常,但是由于采用了TypeScript来编写,“defaults”那里此时会冒红,而且持续集成的编译不会通过,鼠标放在defaults上会提示TS2322: type 'xxxx' is not assignable to  type 'xxxx'。意思是类型对应不上,要求你defaults里面的参数必须和StudentModel里面定义的完全一致,少一个都不行,我不知道为什么会这样,难道sequelize没有对typescript做优化吗?defaults里面如果把所有参数都填上,怪怪的,我id是自增的,肯定不能给id默认值,所以赋给null,where条件里面已经填了两个参数还要再填一遍,没办法先编译通过再说,改正后如下:

await StudentModel.findOrCreate(
    {
        where: {name: `${name}`, tel: `${tel}`},
        defaults: {id:null,
            name: `${name}`,
            tel: `${tel}`,
            age: `${age}`,
            createTime: `${time}`,
            updateTime: `${time}`}
    });

      再来说第二个问题:sequelize的api有一个回调方法,有的是then,有的是spread,这里根据官网文档使用spread将结果切分为俩个部分,一个是返回的实例对象,一个是行为布尔值,我是这么理解的。

await StudentModel.findOrCreate(
    {
        where: {name: `${name}`, tel: `${tel}`},
        defaults: {id:null,
            name: `${name}`,
            tel: `${tel}`,
            age: 21,
            createTime: `${time}`,
            updateTime: `${time}`}
    })
    .spread((student, created) => {
        // 如果找到则直接更新,没找到会自动创建
        if (created === false) {
            (async () => {
                await StudentModel.update(
                    {age: 22, updateTime: `${time}`},
                    {where: {id: student.id}});
            })();
        }
    });

     此处不管是找到也好,创建的也好,spread第一个参数返回的都是student对象,然后紧接着我会用到student对象的属性id值,本地执行也是正常的,但就是在student.id那里冒红 ,也是报TS2322啥的,意思是说student是object类型的无法点出id属性。后来问了web前端工程师,他说要对spread的第一个参数student加个类型,要加类型就要先定义类型,这样写:

interface Student {
    id:number;
    name?:string;
    ...
    ...
}

    定义好以后 ,对spread的第一个参数student加个类型,如下所示

.spread((student: Student, created) => { 

    当然了,如果你嫌麻烦,也可以直接将其定义为any类型,对象依然是原来的那个对象,只是让typescript不再报语法错误

.spread((student: any, created) => { 

    这次student.id不再冒红了。我说我已经定义了一个StudentModel,这里的类型换成StudentModel怎么也冒红,他说typescript里面有专门定义自己属性的接口,不能混淆。

    其实sequelize还有一个叫upsert的API,是updateOrInsert的简称,where条件里面必须包含能定为一条记录的唯一索引,否则无效,就拿上面的例子来说,如果你能获取到id值,则上面的写法可以换成upsert一个api就够了,很精简。

    最后如果使用了sequelize后,启动时控制台报这个错

sequelize deprecated String based operators are now deprecated. Please use Symbol based operators for better security, read more at

   此时可以这么做,修改你的sequelize.ts文件,重点在于operatorsAliases这一大堆:

const Op = Sequelize.Op;
export const sequelize = new Sequelize(dbConfig.database, dbConfig.user, dbConfig.password, {
  host: dbConfig.host,
  port: dbConfig.port,
  dialect: 'mysql',
  operatorsAliases: {
      $eq: Op.eq,
      $ne: Op.ne,
      $gte: Op.gte,
      $gt: Op.gt,
      $lte: Op.lte,
      $lt: Op.lt,
      $not: Op.not,
      $in: Op.in,
      $notIn: Op.notIn,
      $is: Op.is,
      $like: Op.like,
      $notLike: Op.notLike,
      $iLike: Op.iLike,
      $notILike: Op.notILike,
      $regexp: Op.regexp,
      $notRegexp: Op.notRegexp,
      $iRegexp: Op.iRegexp,
      $notIRegexp: Op.notIRegexp,
      $between: Op.between,
      $notBetween: Op.notBetween,
      $overlap: Op.overlap,
      $contains: Op.contains,
      $contained: Op.contained,
      $adjacent: Op.adjacent,
      $strictLeft: Op.strictLeft,
      $strictRight: Op.strictRight,
      $noExtendRight: Op.noExtendRight,
      $noExtendLeft: Op.noExtendLeft,
      $and: Op.and,
      $or: Op.or,
      $any: Op.any,
      $all: Op.all,
      $values: Op.values,
      $col: Op.col
  },
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  },
});

  参考https://stackoverflow.com/questions/46608382/sequelize-deprecated-error-message 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章