node.jstypeormnode.js-typeorm

Why is inverseSide of @ManyToOne not hydrated on entity save?


Starting from default npx typeorm init project:

@Entity()
export class A {
    @PrimaryGeneratedColumn()
    id!: number

    @OneToMany(() => B, (b) => b.a)
    bs: B[]

    constructor(bs: B[]) {
        this.bs = bs
    }
}
@Entity()
export class B {
    @PrimaryGeneratedColumn()
    id!: number

    @ManyToOne(() => A, (a) => a.bs)
    a: A

    constructor(a: A) {
        this.a = a
    }
}
AppDataSource.initialize().then(async () => {

    const a = await AppDataSource.manager.save(new A([]))
    await AppDataSource.manager.save(new B(a))
    await AppDataSource.manager.save(new B(a))
    await AppDataSource.manager.save(new B(a))
    console.log(a.bs.length)

}).catch(error => console.log(error))

This displays 0 (a.bs is still empty).

I would expect that a.bs is hydrated with the saved B's. Isnt that the whole purpose of supplying an inverse mapping on the @ManyToOne anyway?

Or, if I'm getting this wrong, what's the proper way of maintaining DB<->model consistency when adding relationed entities?


Solution

  • Your mapping definitions are correct. The issue is that the object a was initialised with empty array for the values of bs and so a.bs.length returns 0.

    While you created multiple records of entity B afterwards. Object a isn't aware of those. Typeorm won't trace or find all entities in your project and refresh them now that some relations/mappings in the database has changed. In order to refresh the mappings, you'll need to reload a from the database:

    await a.reload();
    

    so that a now knows about the updated mappings.