Skip to content

Child entities' wrong discriminator value when embedded in parent entity #7558

@OoDeLally

Description

@OoDeLally

Issue Description

Here are my 3 entities: Each person can have a given number of animal, which can be either cat or dog.

@Entity({ name: 'person' })
export class PersonEntity extends BaseEntity {
  @PrimaryColumn()
  id!: number;

  @OneToMany(() => AnimalEntity, ({ person }: AnimalEntity) => person, {
    onDelete: 'CASCADE',
    cascade: true,
  })
  pets!: AnimalEntity[];
}


@Entity({ name: 'beings' })
@TableInheritance({ column: { type: 'varchar', name: 'type' } })
export class BeingEntity extends BaseEntity {
  @PrimaryColumn()
  id!: number;
}



@ChildEntity('animal')
export class AnimalEntity extends BaseEntity {
  @Column({ type: 'varchar' })
  name!: string;
}

@ChildEntity('cat')
export class CatEntity extends AnimalEntity {
  // Cat stuff
}

@ChildEntity('dog')
export class DogEntity extends AnimalEntity {
  // Dog stuff
}

Expected Behavior

const pets = [
  this.catRepo.create({
    name: 'felix',
    // Cat stuff
  }),
  this.dogRepo.create({
    name: 'spike',
    // Dog stuff
  }),
];
const person = this.personRepo.create({ pets });


await this.connection.manager.save(person);
// Created [
//     { type: 'cat', personId: 42, name: 'felix', other cat stuff }, 
//     { type: 'dog', personId: 42, name: 'spike', other dog stuff }, 
//     { id: 42, people stuff }
//  ]

Actual Behavior

// Created [
//     { type: 'animal', personId: 42, name: 'felix', other cat stuff }, 
//     { type: 'animal', personId: 42, name: 'spike', other dog stuff }, 
//     { id: 42, people stuff }
//  ]

As you can see, once the animal entities as embedded to a person, then they lose their specific type.
The entity manager saves them as animal (probably because person declare an animal and not a specific species).

Workaround

const pets = [
  this.catRepo.create({
    name: 'felix',
    personId: 42, // assuming i know the personId in advance
    // Cat stuff
  }),
  this.dogRepo.create({
    name: 'spike',
    personId: 42, // assuming i know the personId in advance
    // Dog stuff
  }),
];
const person = this.personRepo.create({  id: 42 });


// What's important here is that the `cat` and `dogs` are saved individually.
// The drawback is that because we dont embed the pet entities, the linking must be done manually.
await this.connection.manager.save([...pets, person]);

// Created [
//     { type: 'cat', personId: 42, name: 'felix', other cat stuff }, 
//     { type: 'dog', personId: 42, name: 'spike', other dog stuff }, 
//     { id: 42, people stuff }
//  ]

Here, it works, probably because the real entity types dog and cat are not morphed-up into animal.

My Environment

Dependency Version
Operating System
Node.js version v15.11.0
Typescript version typescript@4.2.3
TypeORM version typeorm@0.2.31

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.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions