onDelete and sync() depends on order of associations
See original GitHub issueThis seems like it may be related to some issues already reported, but I couldn’t quite find it. Apologies if it’s a duplicate.
What you are doing?
Here are two minimal models, and two orders of adding associations between them.
const Sequelize = require("sequelize");
const sequelize = new Sequelize(/*...*/);
let a = sequelize.define("a", {
id: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true },
}, {freezeTableName: true, timestamps: false});
let b = sequelize.define("b", {
id: { type: Sequelize.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true },
aId: { type: Sequelize.INTEGER, allowNull: false }
}, {freezeTableName: true, timestamps: false});
if (process.argv[2] == "1") {
a.hasMany(b);
b.belongsTo(a);
} else {
b.belongsTo(a);
a.hasMany(b);
}
sequelize.sync({force: true, logging: console.log}).then(() => process.exit(0));```
What do you expect to happen?
The created foreign key probably shouldn’t depend on whether we’re in case 1 or 2.
What is actually happening?
$ node test.js 1 | grep CREATE
Executing (default): CREATE TABLE IF NOT EXISTS "a" ("id" SERIAL , PRIMARY KEY ("id"));
Executing (default): CREATE TABLE IF NOT EXISTS "b" ("id" SERIAL , "aId" INTEGER NOT NULL
REFERENCES "a" ("id") ON DELETE CASCADE ON UPDATE CASCADE, PRIMARY KEY ("id"));
$ node test.js 2 | grep CREATE
Executing (default): CREATE TABLE IF NOT EXISTS "a" ("id" SERIAL , PRIMARY KEY ("id"));
Executing (default): CREATE TABLE IF NOT EXISTS "b" ("id" SERIAL , "aId" INTEGER NOT NULL
REFERENCES "a" ("id") ON DELETE NO ACTION ON UPDATE CASCADE, PRIMARY KEY ("id"));
Note that the foreign key has ON DELETE CASCADE
in case 1, but ON DELETE NO ACTION
in case 2. I think the problem is that hasMany
(and hasOne
?) default to onDelete: "CASCADE"
, while belongsTo
(and belongsToMany
?) default to onDelete: "NO ACTION"
.
Dialect: postgres Database version: 9.3.14 Sequelize version: 3.24.2
Issue Analytics
- State:
- Created 7 years ago
- Comments:8 (1 by maintainers)
Top Results From Across the Web
Sequelize.js onDelete: 'cascade' is not deleting records ...
I had to put onDelete: 'CASCADE' not only on the association definition, but as well in the migration file. // in models/user.js User.associate ......
Read more >Associations - Sequelize
The order in which the association is defined is relevant. ... This way, calling Bar.sync() after the above will yield the following SQL...
Read more >Associations - Manual | Sequelize
Cyclic dependencies & Disabling constraints. Adding constraints between tables means that tables must be created in the database in a certain order, when...
Read more >Working with Associations - Doctrine Object Relational ...
Changes to associations in your code are not synchronized to the database directly, only when calling EntityManager#flush() .
Read more >Loose foreign keys - GitLab Docs
The LooseForeignKeys::CleanupWorker has its database query builder which depends on Arel . The feature doesn't reference any application-specific ActiveRecord ...
Read more >
Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free
Top Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
I believe the problem is that belongTo’s default value of ON DELETE in the code is SET NULL or NO ACTION. The documentation clearly states that for 1:1 and 1:m associations the default value for delete should be SET NULL or CASCADE (depending if the foreign key allows null). The other 1:1 and 1:m associations (hasOne, hasMany) have the correct default value for ON DELETE.
The proper solution might also involve not setting an association’s options to the defaults until sync() is called, so that with a pair of associations, the 2nd association evaluated can overwrite those options if they weren’t explicitly defined by the user on the 1st association. That way I don’t have to define all the same options on both associations of a pair, not knowing which model/association would get evaluated first (using ‘sequelize init:models’ the index.js loads the models and their associations in an ordering that isn’t guaranteed, so right now I have to define the options on both Models to be safe)
I’ve hit this too, my reproduction case FWIW:
Dialect: mysql Database version: 5.7.21 Sequelize version: 4.34.0