简体   繁体   中英

(Added SQL) Sequelize hasMany association with option

I'm new to Sequelize and I'm learning with the official tutorial site( http://docs.sequelizejs.com/manual/tutorial/ ) I got stuck while trying the code on the tutorial.

The code I tried was this:

 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(); 

When I run this code, node console gives me back an error:

"Unhandled rejection SequelizeDatabaseError: Failed to add the foreign key constraint. Missing index for constraint 'cities_ibfk_1' in the referenced table 'countries'"

Could anybody give me what is wrong with this? I really appreciate your help. Thank you.

The code above is from Assotiation part of the tutorial ( http://docs.sequelizejs.com/manual/tutorial/associations.html ) One-to Many associations.


I also attach the code auto-generated by 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;

In glance it doesn't seem SQL syntax is wrong here, but anyhow this makes the error. Can anyone figure out what is wrong? Or is this a problem of Sequelize?

This error occurred because the example code in Sequelize tutorial has an syntax error.

If we want to make rule for a foreign key, it has to reference the primary key of the referenced table. The problem is that in the code, the foreign key countryCode is trying to reference the isoCode of Country model(which is countries table in real MySQL DB).

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'});

The Sequelize code above will be converted into SQL statement like this below:

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;

To make this syntax error fixed, we have to make isoCode of City model a primary key. Let's fix the code:

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

As we fixed the model definition, the code will be working fine as we expected!

But what I wonder is... how could the official tutorial post this code and let the beginners just try out it without knowing that this would not work. Of course, someone would say this is not a problem of Sequelize, but rather the problem of understanding SQL. But still I think the tutorial should be fixed to avoid this kind of happening.


The limitation of this solution is that, there is no point of using the option sourceKey and targetKey , because even without them, Sequelize will automatically figure out the relationship and recognize what is the source key and target key among the tables.

Still I don't get the point... I think for now, I just have to not use the sourceKey and targetkey options.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM