(已添加SQL)Sequelize hasMany与选项

时间:2019-01-03 22:40:56

标签: javascript mysql sql database sequelize.js

我是Sequelize的新手,并且正在通过官方教程网站(http://docs.sequelizejs.com/manual/tutorial/)学习 在尝试本教程中的代码时,我陷入了困境。

我尝试的代码是这样的:

const City = sequelize.define('city', { countryCode: Sequelize.STRING });
const Country = sequelize.define('country', { isoCode: Sequelize.STRING });

Country.hasMany(City, {foreignKey: 'countryCode', sourceKey: 'isoCode'});
City.belongsTo(Country, {foreignKey: 'countryCode', targetKey: 'isoCode'});

sequelize.sync();

运行此代码时,节点控制台会给我一个错误:

  

“未处理的拒绝SequelizeDatabaseError:无法添加外键约束。在引用表'countries'中缺少约束'cities_ibfk_1'的索引””

有人能告诉我这是什么问题吗?非常感谢您的帮助。谢谢。

上面的代码来自本教程的关联部分(http://docs.sequelizejs.com/manual/tutorial/associations.html) 一对多关联。


我还附上了Sequelize自动生成的代码:

CREATE TABLE IF NOT EXISTS `countries` (
  `id` INTEGER NOT NULL auto_increment ,
  `isoCode` VARCHAR(255),
  `createdAt` DATETIME NOT NULL,
  `updatedAt` DATETIME NOT NULL,
  PRIMARY KEY (`id`))
  ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `cities` (
  `id` INTEGER NOT NULL auto_increment ,
  `createdAt` DATETIME NOT NULL,
  `updatedAt` DATETIME NOT NULL,
  `countryCode` VARCHAR(255),
  PRIMARY KEY (`id`),
  FOREIGN KEY (`countryCode`) REFERENCES `countries` (`isoCode`)
  ON DELETE SET NULL ON UPDATE CASCADE)
  ENGINE=InnoDB;

乍一看似乎SQL语法在这里不是错误的,但是无论如何这都会导致错误。任何人都可以找出问题所在吗?还是这是Sequelize的问题?

1 个答案:

答案 0 :(得分:1)

发生此错误是因为Sequelize教程中的示例代码存在语法错误。

如果我们要为外键制定规则,则它必须引用被引用表的主键。问题在于,在代码中,外键countryCode试图引用isoCode模型(在真实的MySQL DB中为Country表)的countries

const City = sequelize.define('city', { countryCode: Sequelize.STRING });
const Country = sequelize.define('country', { isoCode: Sequelize.STRING });

Country.hasMany(City, {foreignKey: 'countryCode', sourceKey: 'isoCode'});
City.belongsTo(Country, {foreignKey: 'countryCode', targetKey: 'isoCode'});

上面的Sequelize代码将转换为如下的SQL语句:

CREATE TABLE IF NOT EXISTS `countries` (
  `id` INTEGER NOT NULL auto_increment ,
  `isoCode` VARCHAR(255),
  `createdAt` DATETIME NOT NULL,
  `updatedAt` DATETIME NOT NULL,
  PRIMARY KEY (`id`))
  ENGINE=InnoDB;

CREATE TABLE IF NOT EXISTS `cities` (
  `id` INTEGER NOT NULL auto_increment ,
  `createdAt` DATETIME NOT NULL,
  `updatedAt` DATETIME NOT NULL,
  `countryCode` VARCHAR(255),
  PRIMARY KEY (`id`),
  FOREIGN KEY (`countryCode`) REFERENCES `countries` (`isoCode`)
  ON DELETE SET NULL ON UPDATE CASCADE)
  ENGINE=InnoDB;

要解决此语法错误,我们必须使isoCode模型中的City为主键。让我们修复代码:

const City = sequelize.define('city', { countryCode: Sequelize.STRING})
const Country = sequelize.define('country', {
  isoCode: {
    type: Sequelize.STRING,
    primaryKey: true
  }
})
// ... the rest of code followed below

修复模型定义后,代码将按预期工作!

但是我想知道的是... 官方教程如何发布此代码,并让初学者在不知道这行不通的情况下尝试一下。当然,有人会说这不是Sequelize的问题,而是理解SQL的问题。但是我仍然认为该教程应该固定以避免这种情况的发生。


此解决方案的局限性在于,没有必要使用选项sourceKeytargetKey,因为即使没有它们,Sequelize也会自动找出关系并识别出源密钥是什么表中的目标键。

我仍然不明白这一点……我想现在,我只需要不使用sourceKey和targetkey选项。