I am facing an issue while trying to save (insert) an entity with cascade of nested relationships (2 levels)
I have 3 entities Item, ItemCustomization and ItemCustomizationOption (Data model diagram attached below)
When I try to save an Item object like below, its failing to insert a record into ItemCustomizationOption.
The child table entries include a foreign key reference to the auto incremented ID field on the parent table. It seems typeorm is not capturing the auto-increment id from the parent row and supplying it to the child inserts.
{ "name": "Cheese Burger", "itemCustomizations": [ { "title": "Sides", "itemCustomizationOptions": [ { "optionItemId": 1, "price": "3" } ] } ] }
query: INSERT INTO "foodspot"."item_customization_option"("item_id", "price", "customization_id", "option_item_id") VALUES (DEFAULT, $1, $2, $3) -- PARAMETERS: [2,5,4] query failed: INSERT INTO "foodspot"."item_customization_option"("item_id", "price", "customization_id", "option_item_id") VALUES (DEFAULT, $1, $2, $3) -- PARAMETERS: [2,5,4] error: { error: null value in column "item_id" violates not-null constraint
// Item.ts
import {
Column,
Entity,
Index,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
import { ItemCustomization } from "./ItemCustomization";
import { ItemCustomizationOption } from "./ItemCustomizationOption";
@Index("PK_item", ["itemId"], { unique: true })
@Entity("item", { schema: "foodspot" })
export class Item {
@PrimaryGeneratedColumn({ type: "integer", name: "item_id" })
itemId: number;
@Column("text", { name: "name" })
name: string;
@Column("money", { name: "price" })
price: string;
@OneToMany(
() => ItemCustomization,
(itemCustomization) => itemCustomization.item, {cascade: ['insert']}
)
itemCustomizations: ItemCustomization[];
}
// ItemCustomization.ts
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
OneToMany,
PrimaryGeneratedColumn,
} from 'typeorm';
import { Item } from './Item';
import { ItemCustomizationOption } from './ItemCustomizationOption';
@Index('PK_item_customization', ['customizationId', 'itemId'], { unique: true })
@Index('fkIdx_item_customization_item', ['itemId'], {})
@Entity('item_customization', { schema: 'foodspot' })
export class ItemCustomization {
@Column('integer', { primary: true, name: 'item_id' })
public itemId: number;
@PrimaryGeneratedColumn({ type: 'integer', name: 'customization_id' })
public customizationId: number;
@Column('text', { name: 'title' })
public title: string;
@ManyToOne(() => Item, (item) => item.itemCustomizations)
@JoinColumn([{ name: 'item_id', referencedColumnName: 'itemId' }])
public item: Item;
@OneToMany(
() => ItemCustomizationOption,
(itemCustomizationOption) => itemCustomizationOption.itemCustomization, {cascade: ['insert']}
)
public itemCustomizationOptions: ItemCustomizationOption[];
}
//ItemCustomizationOption.ts
import {
Column,
Entity,
Index,
JoinColumn,
ManyToOne,
} from 'typeorm';
import { ItemCustomization } from './ItemCustomization';
import { Item } from './Item';
@Index(
'PK_item_customization_option',
['customizationId', 'itemId', 'optionItemId'],
{ unique: true }
)
@Index(
'fkIdx_item_customization_option_item_customization',
['customizationId', 'itemId'],
{}
)
@Index('fkIdx_item_customization_option_option_item', ['optionItemId'], {})
@Entity('item_customization_option', { schema: 'foodspot' })
export class ItemCustomizationOption {
@Column('integer', { primary: true, name: 'item_id' })
public itemId: number;
@Column('money', { name: 'price' })
public price: string;
@Column('integer', { primary: true, name: 'customization_id' })
public customizationId: number;
@Column('integer', { primary: true, name: 'option_item_id' })
public optionItemId: number;
@ManyToOne(
() => ItemCustomization,
(itemCustomization) => itemCustomization.itemCustomizationOptions
)
@JoinColumn([
{ name: 'item_id', referencedColumnName: 'itemId' },
{ name: 'customization_id', referencedColumnName: 'customizationId' },
])
public itemCustomization: ItemCustomization;
}
