Reputation: 1892
I have 2 migrations Users and Posts and Posts has a onDelete: 'CASCADE'
. For some reason when I delete a User with a Posts it throws an error saying:
"Cannot delete or update a parent row: a foreign key constraint fails (`development_db`.`posts`, CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`userId`) REFERENCES `users` (`id`))",
but I already set my Posts entity to onDelete: 'CASCADE'
. What trips me off is when I add ON DELETE CASCADE
on my posts migration the cascade delete works even though I removed onDelete: 'CASCADE'
on my posts model. Any idea? so what's the use of onDelete
in typeorm when you can set it on migration and not on the entity but still works.
USER Migration:
/* eslint-disable class-methods-use-this */
import { MigrationInterface, QueryRunner } from 'typeorm';
export class UsersTable1575433829516 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`
CREATE TABLE users (
id INT AUTO_INCREMENT,
username VARCHAR(50) NOT NULL,
email VARCHAR(50) NOT NULL UNIQUE,
password VARCHAR(255) NOT NULL,
createdAt DATETIME NOT NULL,
PRIMARY KEY(id)
);
`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropTable('users', true);
}
}
POST Migration:
/* eslint-disable class-methods-use-this */
import { MigrationInterface, QueryRunner } from 'typeorm';
export class PostsTable1581617587575 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`
CREATE TABLE posts (
id INT AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
body TEXT(65000) NOT NULL,
createdAt DATETIME NOT NULL,
updatedAt DATETIME,
PRIMARY KEY(id),
userId INT NOT NULL,
FOREIGN KEY (userId)
REFERENCES users (id)
);
`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropTable('posts', true);
}
}
Upvotes: 1
Views: 10765
Reputation: 196
I was running into this same error message ("Cannot delete or update a parent row: a foreign key constraint fails"
) because I had put the onDelete: 'CASCADE'
in the @OneToMany
decorator, instead of the @ManyToOne
decorator, where it needed to be in order to generate the migration correctly.
Here's what didn't work for me:
@Entity()
export class User {
//...
@OneToMany(() => Post, (post) => post.user, { onDelete: 'CASCADE' })
public posts: Post[];
//...
}
Here's what worked for me:
@Entity()
export class Post {
// ...
@ManyToOne(() => User, (user) => user.posts, { onDelete: 'CASCADE' })
public user: User;
// ...
}
I'm guessing this is the issue, because based on one of your comments, it sounds like you're coming from the Rails world. In Rails, you specify the 'cascade delete' on the 'One' side (has_many :posts, dependent: :destroy
). In contrast, TypeORM seems to need it on the 'Many' side.
Upvotes: 10
Reputation: 1
Just add to your migration the property ON DELETE, like this !
/* eslint-disable class-methods-use-this */
import { MigrationInterface, QueryRunner } from 'typeorm';
export class PostsTable1581617587575 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<any> {
await queryRunner.query(`
CREATE TABLE posts (
id INT AUTO_INCREMENT,
title VARCHAR(255) NOT NULL,
body TEXT(65000) NOT NULL,
createdAt DATETIME NOT NULL,
updatedAt DATETIME,
PRIMARY KEY(id),
userId INT NOT NULL,
FOREIGN KEY (userId)
REFERENCES users (id)
ON DELETE CASCADE
);
`);
}
public async down(queryRunner: QueryRunner): Promise<any> {
await queryRunner.dropTable('posts', true);
}
}
Upvotes: 0