NodeJS sequelize 自动生成模型并运行迁移 SQL 语法错误

Posted

技术标签:

【中文标题】NodeJS sequelize 自动生成模型并运行迁移 SQL 语法错误【英文标题】:NodeJS sequelize auto generate models and run migrations SQL syntax error 【发布时间】:2019-09-27 09:26:25 【问题描述】:

我正在使用 mysql 构建一个新的 NodeJS 应用程序。我需要使用现有的数据库模式。我有一个加载到数据库中的 mysql 转储文件(在 docker 容器中)。我正在尝试自动生成模型和迁移,然后成功运行迁移。我能够生成模型和迁移,但是运行生成的迁移时出现 SQL 语法错误。

以下是相关版本:

Node10-高山

"mysql": "^2.17.1",
"mysql2": "^1.6.5",
"sequelize": "^5.8.5",
"sequelize-auto": "^0.4.29",
"sequelize-auto-migrations": "^1.0.3"

我使用sequelize-auto 模块自动生成模型。这行得通。

sequelize-auto -o "./models" -d sequelize_auto_test -h localhost -u username -p 5432 -x password -e mysql

然后我尝试使用 sequelize-auto-migrations 模块生成迁移,然后自动运行它们。

生成初始迁移文件有效。

node ./node_modules/sequelize-auto-migrations/bin/makemigration --name <initial_migration_name>

但是,在运行实际迁移时,会出现语法错误。

node ./node_modules/sequelize-auto-migrations/bin/runmigration

这适用于许多表,但随后会遇到语法错误。

     code: 'ER_PARSE_ERROR',
     errno: 1064,
     sqlState: '42000',
     sqlMessage:
      '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 \') ENGINE=InnoDB\' at line 1',
     sql: 'CREATE TABLE IF NOT EXISTS `osw` () ENGINE=InnoDB;' ,
  sql: 'CREATE TABLE IF NOT EXISTS `osw` () ENGINE=InnoDB;' 

这里是相关的模型osw.js(由sequelize-auto模块生成):

/* jshint indent: 2 */

module.exports = function(sequelize, DataTypes) 
  return sequelize.define('osw', 
    OSWID: 
      type: DataTypes.INTEGER(10).UNSIGNED,
      allowNull: false,
      primaryKey: true
    ,
    IdentificationID: 
      type: DataTypes.INTEGER(10).UNSIGNED,
      allowNull: true,
      references: 
        model: 'itemidentification',
        key: 'IdentificationID'
      
    ,
    ProposedHours: 
      type: DataTypes.DECIMAL,
      allowNull: true
    ,
    WorkStartDate: 
      type: DataTypes.DATEONLY,
      allowNull: true
    ,
    WorkEndDate: 
      type: DataTypes.DATEONLY,
      allowNull: true
    ,
    FormatID: 
      type: DataTypes.INTEGER(10).UNSIGNED,
      allowNull: true,
      references: 
        model: 'formats',
        key: 'FormatID'
      
    ,
    WorkLocationID: 
      type: DataTypes.INTEGER(10).UNSIGNED,
      allowNull: true
    
  , 
    tableName: 'osw'
  );
;

这里是mysql转储文件的相关部分:

CREATE TABLE `OSW` (
  `OSWID` int(10) unsigned NOT NULL AUTO_INCREMENT,
  `IdentificationID` int(10) unsigned DEFAULT NULL,
  `ProposedHours` decimal(10,2) DEFAULT NULL,
  `WorkStartDate` date DEFAULT NULL,
  `WorkEndDate` date DEFAULT NULL,
  `FormatID` int(10) unsigned DEFAULT NULL,
  `WorkLocationID` int(10) unsigned DEFAULT NULL,
  PRIMARY KEY (`OSWID`),
  KEY `OSW_FKIndex1` (`IdentificationID`),
  KEY `OSW_Format` (`FormatID`),
  CONSTRAINT `OSW_Format` FOREIGN KEY (`FormatID`) REFERENCES `formats` (`formatid`) ON DELETE SET NULL,
  CONSTRAINT `OSW_Ident` FOREIGN KEY (`IdentificationID`) REFERENCES `itemidentification` (`identificationid`) ON DELETE CASCADE
) ENGINE=InnoDB AUTO_INCREMENT=1147 DEFAULT CHARSET=utf8 PACK_KEYS=0;

更新:我认为问题可能与自动生成的迁移有关。迁移文件似乎缺少列和字段类型定义,因此这可能是 SQL CREATE table 命令缺少列名的原因。以下是针对osw 表生成的迁移文件的相关部分:

var migrationCommands = [
    
        fn: "createTable",
        params: [
            "osw",
            

            ,
            
        ]
    
];

【问题讨论】:

【参考方案1】: 是的,SQL 错误是因为括号之间应该有一个列列表。 是的,迁移文件应包含列而不是空括号,如本答案下方的正确文件所示。 错误迁移的原因似乎与您的 package.json 中指定的最新 Sequelize 版本有关。这个答案的其余部分解释了这个过程。

您的 sequelize-auto 输出看起来很正常,因此我尝试仅重现迁移步骤:

    在新目录中运行 sequelize init(未明确安装,NPM 显示 4.44)并将 osw.js 粘贴到 ./models 中。 安装 mysql2 和 sequelize-auto-migrations 的匹配版本,调用 node ./node_modules/sequelize-auto-migrations/bin/makemigration --name osw 的最低要求 这产生了 migrations/1-osw.js:
'use strict';

var Sequelize = require('sequelize');

/**
 * Actions summary:
 *
 * createTable "osw", deps: [itemidentification, formats]
 *
 **/

var info = 
    "revision": 1,
    "name": "osw",
    "created": "2019-05-30T03:54:19.054Z",
    "comment": ""
;

var migrationCommands = [
    fn: "createTable",
    params: [
        "osw",
        
            "OSWID": 
                "type": Sequelize.INTEGER(10).UNSIGNED,
                "field": "OSWID",
                "primaryKey": true,
                "allowNull": false
            ,
            "IdentificationID": 
                "type": Sequelize.INTEGER(10).UNSIGNED,
                "field": "IdentificationID",
                "references": 
                    "model": "itemidentification",
                    "key": "IdentificationID"
                ,
                "allowNull": true
            ,
            "ProposedHours": 
                "type": Sequelize.DECIMAL,
                "field": "ProposedHours",
                "allowNull": true
            ,
            "WorkStartDate": 
                "type": Sequelize.DATEONLY,
                "field": "WorkStartDate",
                "allowNull": true
            ,
            "WorkEndDate": 
                "type": Sequelize.DATEONLY,
                "field": "WorkEndDate",
                "allowNull": true
            ,
            "FormatID": 
                "type": Sequelize.INTEGER(10).UNSIGNED,
                "field": "FormatID",
                "references": 
                    "model": "formats",
                    "key": "FormatID"
                ,
                "allowNull": true
            ,
            "WorkLocationID": 
                "type": Sequelize.INTEGER(10).UNSIGNED,
                "field": "WorkLocationID",
                "allowNull": true
            ,
            "createdAt": 
                "type": Sequelize.DATE,
                "field": "createdAt",
                "allowNull": false
            ,
            "updatedAt": 
                "type": Sequelize.DATE,
                "field": "updatedAt",
                "allowNull": false
            
        ,
        
    ]
];

module.exports = 
    pos: 0,
    up: function(queryInterface, Sequelize)
    
        var index = this.pos;
        return new Promise(function(resolve, reject) 
            function next() 
                if (index < migrationCommands.length)
                
                    let command = migrationCommands[index];
                    console.log("[#"+index+"] execute: " + command.fn);
                    index++;
                    queryInterface[command.fn].apply(queryInterface, command.params).then(next, reject);
                
                else
                    resolve();
            
            next();
        );
    ,
    info: info
;

这解决了眼前的问题,但没有解释它。我清理了目录,初始化了包,安装了所有依赖项,并尝试再次生成迁移。这产生了一个空的 migrationCommands 变量,就像您在上面显示的那样。尝试卸载并重新安装各种软件包没有效果 - 我生成了十几次空包。卸载 sequelize 导致错误,所以我从一个空目录和 npm i -s mysql2 sequelize-auto-migrations; sequelize init 重新开始。从 osw.js 生成再次起作用。

npm 显示 sequelize-auto-migrations 再次使用 sequelize 4.44。 npm i sequelize 安装了 5.8.7,生成立即开始失败。所以 sequelize-auto-migrations 只能在依赖于早期版本的 sequelize 时为您的模型生成。不知道根本原因是什么。

【讨论】:

以上是关于NodeJS sequelize 自动生成模型并运行迁移 SQL 语法错误的主要内容,如果未能解决你的问题,请参考以下文章

Nodejs / PostgreSQL sequelize - 如何更新/更改数据库中的模型?

nodejs使用sequelize操作mysql实例

nodejs使用Sequelize框架操作数据库

在 MySQL 中使用 sequelize 自动递增 id

NodeJs Sequelize 删除 toJSON 方法中的属性会导致模型本身的值被删除

nodejs: express sequelize-cli