aRtoo
aRtoo

Reputation: 1892

how to use onDelete: 'CASCADE' on TypeORM

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

Answers (2)

Schleicher
Schleicher

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

Stefferson Thallys
Stefferson Thallys

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

Related Questions