Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cascade doesn't work with nullable relationship #7091

Open
2 of 21 tasks
davidbnk opened this issue Nov 19, 2020 · 7 comments
Open
2 of 21 tasks

Cascade doesn't work with nullable relationship #7091

davidbnk opened this issue Nov 19, 2020 · 7 comments

Comments

@davidbnk
Copy link

Issue Description

I feel I might be missing something but ManyToOne with cascade won't work for me if:

  • Have an entity with to cascade ManyToOne relationships, one nullable and the other not
  • Use a client side generated id for the nullable relationship

Expected Behavior

Should respect cascade and save both relationships

Actual Behavior

The nullable relationship cascade won't work and the main entity insert will throw an error: Cannot add or update a child row: a foreign key constraint fails

Steps to Reproduce

import "reflect-metadata";
import { createConnection } from "typeorm";
import { Product } from "./entity/Product";
import { Category } from "./entity/Category";
import { Video } from "./entity/Video";

(async function () {
  const connection = await createConnection();
  await connection.synchronize();

  const category = new Category();
  category.name = 'Category name';

  const video = new Video();
  video.id = 3;
  video.url = 'https://example.com/';

  const product = new Product();
  product.title = 'Product title';
  product.category = category;
  product.video = video;

  await connection.getRepository(Product).save(product);
  await connection.close();
})();
import { Column, Entity, ManyToOne, PrimaryGeneratedColumn } from "typeorm";
import { Category } from "./Category";
import { Video } from "./Video";

@Entity()
export class Product {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  title!: string;

  @ManyToOne((type) => Video, (video) => video.products, {
    cascade: true,
    nullable: true,
  })
  video?: Video;

  @ManyToOne((type) => Category, (category) => category.products, {
    cascade: true,
    nullable: false,
  })
  category!: Category;
}
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { Product } from "./Product";

@Entity()
export class Category {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  name!: string;

  @OneToMany((type) => Product, (product) => product.category)
  products!: Product[];
}
import { Column, Entity, OneToMany, PrimaryGeneratedColumn } from "typeorm";
import { Product } from "./Product";

@Entity()
export class Video {
  @PrimaryGeneratedColumn()
  id: number;

  @Column()
  url!: string;

  @OneToMany((type) => Product, (product) => product.video)
  products!: Product[];
}
query: SELECT `Video`.`id` AS `Video_id`, `Video`.`url` AS `Video_url` FROM `video` `Video` WHERE `Video`.`id` IN (?) -- PARAMETERS: [3]
query: START TRANSACTION
query: INSERT INTO `category`(`id`, `name`) VALUES (DEFAULT, ?) -- PARAMETERS: ["Category name"]
query: INSERT INTO `product`(`id`, `title`, `videoId`, `categoryId`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["Product title",3,1]
query failed: INSERT INTO `product`(`id`, `title`, `videoId`, `categoryId`) VALUES (DEFAULT, ?, ?, ?) -- PARAMETERS: ["Product title",3,1]
error: Error: Cannot add or update a child row: a foreign key constraint fails (`db`.`product`, CONSTRAINT `FK_9d88d1768fab22374261a10f029` FOREIGN KEY 
(`videoId`) REFERENCES `video` (`id`))
    at Packet.asError (C:\Users\David\Desktop\bug\node_modules\mysql2\lib\packets\packet.js:712:17)
    at Query.execute (C:\Users\David\Desktop\bug\node_modules\mysql2\lib\commands\command.js:28:26)
    at PoolConnection.handlePacket (C:\Users\David\Desktop\bug\node_modules\mysql2\lib\connection.js:425:32)
    at PacketParser.onPacket (C:\Users\David\Desktop\bug\node_modules\mysql2\lib\connection.js:75:12)
    at PacketParser.executeStart (C:\Users\David\Desktop\bug\node_modules\mysql2\lib\packet_parser.js:75:16)
    at Socket.<anonymous> (C:\Users\David\Desktop\bug\node_modules\mysql2\lib\connection.js:82:25)
    at Socket.emit (events.js:315:20)
    at Socket.EventEmitter.emit (domain.js:486:12)
    at addChunk (_stream_readable.js:309:12)
    at readableAddChunk (_stream_readable.js:284:9) {
  code: 'ER_NO_REFERENCED_ROW_2',
  errno: 1452,
  sqlState: '23000',
  sqlMessage: 'Cannot add or update a child row: a foreign key constraint fails (`db`.`product`, CONSTRAINT `FK_9d88d1768fab22374261a10f029` FOREIGN KEY (`videoId`) REFERENCES `video` (`id`))'
}
query: ROLLBACK

My Environment

Dependency Version
Operating System Windows 10
Node.js version 14.15.0
Typescript version 3.3.3333
TypeORM version 0.2.29

Additional Context

The bug won't occur if:

  • The client side generated id is removed (video.id = 3;)
  • The client side generated id is kept but the relationship between Product and Category is removed

Relevant Database Driver(s)

  • aurora-data-api
  • aurora-data-api-pg
  • better-sqlite3
  • cockroachdb
  • cordova
  • expo
  • mongodb
  • mysql
  • nativescript
  • oracle
  • postgres
  • react-native
  • sap
  • sqlite
  • sqlite-abstract
  • sqljs
  • sqlserver

Are you willing to resolve this issue by submitting a Pull Request?

  • Yes, I have the time, and I know how to start.
  • Yes, I have the time, but I don't know how to start. I would need guidance.
  • No, I don't have the time, although I believe I could do it if I had the time...
  • No, I don't have the time and I wouldn't even know how to start.
@nebkat
Copy link
Contributor

nebkat commented Nov 20, 2020

I might be wrong, but I think this is because the video isn't saved yet in the database. It is attempting to set videoId to 3 based on the object you gave it, and at that moment that doesn't exist. Cascade will work for DELETE/UPDATE, but has no effect on INSERT.

@davidbnk
Copy link
Author

davidbnk commented Nov 20, 2020

That was my assumption too, but if you remove the relationship between Product and Category, you can set an id to video and it will work fine (the video will get inserted with id 3 before product). I found this behavior strange because adding or removing a relationship shouldn't affect how the cascade of the other relationship functions

@demorose
Copy link
Contributor

demorose commented Apr 6, 2022

Having the same issue with postgres

@DanielBlytheCTO
Copy link

Having similar issue with postgres. Any update on this?

@pacop
Copy link

pacop commented Jun 16, 2023

Same issue here with postgres. Any update on this?

@venuziano
Copy link

Same issue here using MySQL.

@romyha
Copy link

romyha commented Apr 30, 2024

Also facing this issue with MySQL. Works as soon as nullable = false, but fails for nullable = true ManyToOne relations.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

8 participants