节点/快速/序列化:数据类型VIRTUAL在db:migration

问题描述

当使用sequelize-cli运行db:migration时,数据类型为Virtual的模型字段和直接从Sequelize手册直接复制的get方法会产生SQL语法错误。通过反复试验排除了文件中的其他任何可能的错误。

MySQL 5.7.31和带有Express 4.17.1和mysql2 2.1.0的Sequelize ^ 6.3.5。

我的迁移文件:

'use strict'
const { DataTypes } = require('sequelize')

module.exports = {
  up: async (queryInterface,Sequelize) => {
    await queryInterface.createTable('users',{
      id: {
        type: DataTypes.UUID,defaultValue: Sequelize.UUIDV4,primaryKey: true,allowNull: false,// constraint on mysql
        unique: true,// constraint on mysql
        validate: {
          isUUID: {
            args: 4,msg: 'User ID must be a UUID4 string.'
          }
        }
      },firstName: {
        type: DataTypes.STRING,required: true,notEmpty: true,validate: {
          len: {
            args: [2,90],msg: 'The first name must contain between 2 and 90 characters.'
          }
        }
      },lastName: {
        type: DataTypes.STRING,msg: 'The last name must contain between 2 and 90 characters.'
          }
        }
      },// Code that breaks the migration process:
      fullName: {
        type: DataTypes.VIRTUAL,get() {
          return `${this.firstName} ${this.lastName}`;
        }
      },// End code that breaks migration process
      email: {
        type: DataTypes.STRING,unique: true,validate: {
          isEmail: {
            args: [true],msg: 'Incorrect email format'
          },isLowercase: {
            args: [true],msg: 'Email address must be lowercase'
          },len: {
            args: [2,50],msg: 'The email address must have between 2 and 50 characters',},notEmpty: {
            args: [true],msg: 'The email field can\'t be empty.'
          },}
      },password: {
        type: DataTypes.STRING,validate: {
          len: {
            args: [8,99],msg: 'Your password must contain at least 8 characters.',msg: 'The password field cannot be empty.'
          }
        }
      },resetPasswordToken: {
        type: DataTypes.STRING
      },resetPasswordExpire: {
        type: DataTypes.INTEGER
      },createdAt: {
        type: DataTypes.DATE,allowNull: false
      },updatedAt: {
        type: DataTypes.DATE,deletedAt: {
        type: DataTypes.DATE
      }
    },{
      paranoid: true,tableName: 'users'
    })
  },down: async (queryInterface,Sequelize) => {
    await queryInterface.dropTable('users');
  }
};

sequelize-cli db:migrate之后的控制台输出:

ERROR: You have an error in your SQL syntax; check the manual that corresponds to your MySQL
server version for the right syntax to use near 'VIRTUAL,`email` VARCHAR(255) 
NOT NULL UNIQUE,`password` VARCHAR(255) NOT NULL,' at line 1

npm ERR! code ELIFECYCLE
npm ERR! errno 1
etc.

如果从模型中删除了fullName字段,则迁移成功运行。

fullName字段中的get()方法与手册(https://sequelize.org/master/manual/getters-setters-virtuals.html#virtual-fields)中的示例相同。

这变得特别有趣,因为Sequelize手册指出虚拟数据类型不会添加到数据库中-这是此功能的重点:

The VIRTUAL field does not cause a column in the table to exist. 
In other words,the model above will not have a fullName column. 
However,it will appear to have it!

环境:

  • 后续版本:^ 6.3.5
  • Node.js版本:12.18.3
  • 操作系统:MacOS / Docker 19.03.13 build 4484c46d9d
  • MySQL 5.7.31
  • Express 4.17.1
  • NPM软件包mysql2 2.1.0版(适配器)
  • 序列化CLI 6.2.0

谢谢您的帮助。

解决方法

Virtuals 的存在是为了帮助您查询模型(例如,在您的 API 控制器中获取用户的全名)。由于它们不存在于数据库中,因此不应将它们作为迁移文件的一部分。

简而言之,您应该在模型定义中使用 VIRTUAL,而不是在使用 queryInterface.createTable 方法的迁移文件中。

希望这能回答您的问题。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...