typeorm: Many to Many (bidirectional) - table path is undefined (bug in documentation?)

Issue type:

[ ] question [x] bug report [ ] feature request [ ] documentation issue

Database system/driver:

[ ] cordova [ ] mongodb [ ] mssql [x] mysql / mariadb [ ] oracle [ ] postgres [ ] sqlite [ ] sqljs [ ] react-native [ ] expo

TypeORM version:

[x] latest [ ] @next [ ] 0.x.x (or put your version here)

Steps to reproduce or a small repository showing the problem: User entity

@Entity()
export class User {
  @PrimaryGeneratedColumn({
    type: "bigint",
    unsigned: true
  })
  id: number;

  @Column("varchar")
  name: string;

  @ManyToMany(type => Role)
  @JoinTable({
    name: "user_role",
    joinColumns: [{ name: "userId" }],
    inverseJoinColumns: [{ name: "roleId" }]
  })
  roles: Role[];
}

Role entity

@Entity()
export class Role {
  @PrimaryGeneratedColumn({
    type: "bigint",
    unsigned: true
  })
  id: number;

  @Column("varchar")
  name: string;

  @ManyToMany(type => User, user => user.roles)
  users: User[];

  @CreateDateColumn()
  createdAt: string;

  @UpdateDateColumn()
  updatedAt: string;
}

Then query:

db
    .getRepository(Role)
    .createQueryBuilder("role")
    .leftJoin("role.users", "user")
    .where("user.id = :id", { id: 1 })
    .getMany();

Error: TypeError: Cannot read property ‘tablePath’ of undefined

Everything is done the same as in documentation: http://typeorm.io/#/many-to-many-relations If I add @JoinTable to the “Role” entity, everything is working fine, but documentation cleary says: “We just made our relation bi-directional. Note, the inverse relation does not have a @JoinTable. @JoinTable must be only on one side of the relation.”

What is more, when the @JoinTable decorator is on both sides, it spoils inserting many to many:

db
 .createQueryBuilder()
 .relation(User, "roles")
 .of(2) //User id
 .add(10); // Role id

It produces query: ‘INSERT INTO user_role(userId, roleId) VALUES (10, 2)’ Foreign keys are switched.

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 10
  • Comments: 22 (1 by maintainers)

Most upvoted comments

you need to replace the following line (in the User entity) @ManyToMany(type => Role) with: @ManyToMany(type => Role, role => role.users)

I had exactly the same problem.

This is how it works for me:

First side of the relationship, Product Entity

  @ManyToMany(() => Showcase, (showcase) => showcase.products)
  @JoinTable()
  showcases: Showcase[];

Second side of the relationship, Showcase Entity

  @ManyToMany(() => Product, (product) => product.showcases )
  products: product[];

Make sure you do not forget both inverseSide functions (showcase) => showcase.products and (product) => product.showcases. Forgetting one of those caused the problem for me.

@mregula I don’t think role => role.users has anything to do with auto-generating/naming the join table.

Have you tried:

  @ManyToMany(type => Role, role => role.users)
  @JoinTable({
    name: "user_role",
    joinColumns: [{ name: "userId" }],
    inverseJoinColumns: [{ name: "roleId" }]
  })
  roles: Role[];

@mregula I believe your problem is on user @ManyToMany. It should look something like

@ManyToMany(type => Role, role => role.users)

For future readers: I accidentally used JoinColumn instead of JoinTable on my Many-To-Many relation.

Debug context

Just ran into this “problem”. I can confirm, the bi-directional many-to-many only works in one way (from the owning side specified with @JoinTable), the other way throws an error.

I tried to do a little digging into the problem. The problem is that TypeOrm is trying to access the relation.junctionEntityMetadata.tablePath property. junctionEntityMetadata is undefined, however, it is available under relation.inverseRelation.junctionEntityMetadata.

Perhaps it there is missing logic to detect an inverse relation? I’m not familiar with the workings of TypeOrm and wouldn’t want to break anything.

Koa 2.8.1, Typeorm 0.2.18, Node 12.9.0, Postgres 11.5

Throwing line: https://github.com/typeorm/typeorm/blob/d1594f5d41a35bac7bb99d4f00e76c2fb670ee17/src/query-builder/SelectQueryBuilder.ts#L1467

The thrown `Error`
"type": "TypeError",
"message": "Cannot read property 'tablePath' of undefined",
"stack":
    TypeError: Cannot read property 'tablePath' of undefined
        at C:\Users\Marcus\Development\mastermovies-api\node_modules\typeorm\query-builder\SelectQueryBuilder.js:1042:73
        at Array.map (<anonymous>)
        at SelectQueryBuilder.createJoinExpression (C:\Users\Marcus\Development\mastermovies-api\node_modules\typeorm\query-builder\SelectQueryBuilder.js:1011:55)
        at SelectQueryBuilder.getQuery (C:\Users\Marcus\Development\mastermovies-api\node_modules\typeorm\query-builder\SelectQueryBuilder.js:43:21)
        at SelectQueryBuilder.getQueryAndParameters (C:\Users\Marcus\Development\mastermovies-api\node_modules\typeorm\query-builder\QueryBuilder.js:224:26)
        at SelectQueryBuilder.<anonymous> (C:\Users\Marcus\Development\mastermovies-api\node_modules\typeorm\query-builder\SelectQueryBuilder.js:1470:50)
        at step (C:\Users\Marcus\Development\mastermovies-api\node_modules\tslib\tslib.js:133:27)
        at Object.next (C:\Users\Marcus\Development\mastermovies-api\node_modules\tslib\tslib.js:114:57)
        at C:\Users\Marcus\Development\mastermovies-api\node_modules\tslib\tslib.js:107:75
        at new Promise (<anonymous>)

Entity objects

Also tried removing custom table names and re-creating all tables.

Film (owning relation)

@Entity({ schema: "glacier" })
export class Film extends FilmMetadata {
  @PrimaryGeneratedColumn("increment")
  public id?: number;

  @Column()
  public name: string;

  @Column()
  public public: boolean;

  @ManyToMany(_type => Key)
  @JoinTable({ name: "film_keys" })
  public keys: Key[];

  @ManyToMany(_type => Group)
  @JoinTable({ name: "film_groups" })
  public groups: Group[];

  @OneToMany(_type => Export, exp => exp.film)
  public exports: Export[];

  @OneToMany(_type => Thumbnail, thumbnail => thumbnail.film)
  public thumbnails: Thumbnail[];
}

Key

@Entity({ schema: "glacier" })
export class Key {
  @PrimaryGeneratedColumn("increment")
  public id?: number;

  @Column({ unique: true })
  public value: string;

  @Column()
  public comment: string;

  @Column({ type: "timestamp", nullable: true })
  public expire?: Date;

  @ManyToMany(_type => Film, film => film.keys)
  public films: Film[];

  @ManyToMany(_type => Group, group => group.keys)
  public groups: Group[];
}
The `relation` object (contains the `undefined` property)

This was dumped just before the error is thrown (see the link above).

EntityMetadata {
  isTreeParent: false,
  isTreeChildren: false,
  isPrimary: false,
  isLazy: false,
  isEager: false,
  persistenceEnabled: true,
  isCascadeInsert: false,
  isCascadeUpdate: false,
  isCascadeRemove: false,
  isNullable: true,
  isOwning: false,
  isOneToOne: false,
  isOneToOneOwner: false,
  isWithJoinColumn: false,
  isOneToOneNotOwner: false,
  isOneToMany: false,
  isManyToOne: false,
  isManyToMany: true,
  isManyToManyOwner: false,
  isManyToManyNotOwner: true,
  foreignKeys: [],
  joinColumns: [],
  inverseJoinColumns: [],
  entityMetadata: EntityMetadata {
    childEntityMetadatas: [],
    inheritanceTree: [ [Function: Key] ],
    tableType: 'regular',
    synchronize: true,
    hasNonNullableRelations: false,
    isJunction: false,
    isClosureJunction: false,
    hasMultiplePrimaryKeys: false,
    hasUUIDGeneratedColumns: true,
    ownColumns: [
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata]
    ],
    columns: [
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata]
    ],
    ancestorColumns: [],
    descendantColumns: [],
    nonVirtualColumns: [
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata]
    ],
    ownerColumns: [],
    inverseColumns: [],
    generatedColumns: [ [ColumnMetadata] ],
    primaryColumns: [ [ColumnMetadata] ],
    ownRelations: [ [Circular], [RelationMetadata] ],
    relations: [ [Circular], [RelationMetadata] ],
    eagerRelations: [],
    lazyRelations: [],
    oneToOneRelations: [],
    ownerOneToOneRelations: [],
    oneToManyRelations: [],
    manyToOneRelations: [],
    manyToManyRelations: [ [Circular], [RelationMetadata] ],
    ownerManyToManyRelations: [],
    relationsWithJoinColumns: [],
    relationIds: [],
    relationCounts: [],
    foreignKeys: [],
    embeddeds: [],
    allEmbeddeds: [],
    ownIndices: [],
    indices: [],
    uniques: [ [UniqueMetadata] ],
    ownUniques: [ [UniqueMetadata] ],
    checks: [],
    exclusions: [],
    ownListeners: [],
    listeners: [],
    afterLoadListeners: [],
    beforeInsertListeners: [],
    afterInsertListeners: [],
    beforeUpdateListeners: [],
    afterUpdateListeners: [],
    beforeRemoveListeners: [],
    afterRemoveListeners: [],
    connection: Connection {
      migrations: [],
      subscribers: [],
      entityMetadatas: [Array],
      name: 'default',
      options: [Object],
      logger: [AdvancedConsoleLogger],
      driver: [PostgresDriver],
      manager: [EntityManager],
      namingStrategy: DefaultNamingStrategy {},
      queryResultCache: undefined,
      relationLoader: [RelationLoader],
      relationIdLoader: [RelationIdLoader],
      isConnected: true
    },
    inheritancePattern: undefined,
    treeType: undefined,
    parentClosureEntityMetadata: undefined,
    tableMetadataArgs: {
      target: [Function: Key],
      name: undefined,
      type: 'regular',
      orderBy: undefined,
      engine: undefined,
      database: undefined,
      schema: 'glacier',
      synchronize: undefined
    },
    target: [Function: Key],
    expression: undefined,
    engine: undefined,
    database: undefined,
    schema: 'glacier',
    givenTableName: undefined,
    targetName: 'Key',
    tableNameWithoutPrefix: 'key',
    tableName: 'key',
    name: 'Key',
    tablePath: 'glacier.key',
    schemaPath: 'glacier',
    orderBy: undefined,
    discriminatorValue: 'Key',
    treeParentRelation: undefined,
    treeChildrenRelation: undefined,
    createDateColumn: undefined,
    updateDateColumn: undefined,
    versionColumn: undefined,
    discriminatorColumn: undefined,
    treeLevelColumn: undefined,
    nestedSetLeftColumn: undefined,
    nestedSetRightColumn: undefined,
    materializedPathColumn: undefined,
    objectIdColumn: undefined,
    propertiesMap: {
      id: 'id',
      value: 'value',
      comment: 'comment',
      expire: 'expire',
      films: 'films',
      groups: 'groups'
    }
  },
  embeddedMetadata: undefined,
  target: [Function: Key],
  propertyName: 'films',
  relationType: 'many-to-many',
  givenInverseSidePropertyFactory: [Function],
  onDelete: undefined,
  onUpdate: undefined,
  deferrable: undefined,
  type: [Function: Film],
  propertyPath: 'films',
  inverseEntityMetadata: EntityMetadata {
    childEntityMetadatas: [],
    inheritanceTree: [ [Function: Film], [Function: FilmMetadata] ],
    tableType: 'regular',
    synchronize: true,
    hasNonNullableRelations: false,
    isJunction: false,
    isClosureJunction: false,
    hasMultiplePrimaryKeys: false,
    hasUUIDGeneratedColumns: true,
    ownColumns: [
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata]
    ],
    columns: [
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata]
    ],
    ancestorColumns: [],
    descendantColumns: [],
    nonVirtualColumns: [
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata],
      [ColumnMetadata]
    ],
    ownerColumns: [],
    inverseColumns: [],
    generatedColumns: [ [ColumnMetadata] ],
    primaryColumns: [ [ColumnMetadata] ],
    ownRelations: [
      [RelationMetadata],
      [RelationMetadata],
      [RelationMetadata],
      [RelationMetadata]
    ],
    relations: [
      [RelationMetadata],
      [RelationMetadata],
      [RelationMetadata],
      [RelationMetadata]
    ],
    eagerRelations: [],
    lazyRelations: [],
    oneToOneRelations: [],
    ownerOneToOneRelations: [],
    oneToManyRelations: [ [RelationMetadata], [RelationMetadata] ],
    manyToOneRelations: [],
    manyToManyRelations: [ [RelationMetadata], [RelationMetadata] ],
    ownerManyToManyRelations: [ [RelationMetadata], [RelationMetadata] ],
    relationsWithJoinColumns: [],
    relationIds: [],
    relationCounts: [],
    foreignKeys: [],
    embeddeds: [],
    allEmbeddeds: [],
    ownIndices: [],
    indices: [],
    uniques: [],
    ownUniques: [],
    checks: [],
    exclusions: [],
    ownListeners: [],
    listeners: [],
    afterLoadListeners: [],
    beforeInsertListeners: [],
    afterInsertListeners: [],
    beforeUpdateListeners: [],
    afterUpdateListeners: [],
    beforeRemoveListeners: [],
    afterRemoveListeners: [],
    connection: Connection {
      migrations: [],
      subscribers: [],
      entityMetadatas: [Array],
      name: 'default',
      options: [Object],
      logger: [AdvancedConsoleLogger],
      driver: [PostgresDriver],
      manager: [EntityManager],
      namingStrategy: DefaultNamingStrategy {},
      queryResultCache: undefined,
      relationLoader: [RelationLoader],
      relationIdLoader: [RelationIdLoader],
      isConnected: true
    },
    inheritancePattern: undefined,
    treeType: undefined,
    parentClosureEntityMetadata: undefined,
    tableMetadataArgs: {
      target: [Function: Film],
      name: undefined,
      type: 'regular',
      orderBy: undefined,
      engine: undefined,
      database: undefined,
      schema: 'glacier',
      synchronize: undefined
    },
    target: [Function: Film],
    expression: undefined,
    engine: undefined,
    database: undefined,
    schema: 'glacier',
    givenTableName: undefined,
    targetName: 'Film',
    tableNameWithoutPrefix: 'film',
    tableName: 'film',
    name: 'Film',
    tablePath: 'glacier.film',
    schemaPath: 'glacier',
    orderBy: undefined,
    discriminatorValue: 'Film',
    treeParentRelation: undefined,
    treeChildrenRelation: undefined,
    createDateColumn: undefined,
    updateDateColumn: undefined,
    versionColumn: undefined,
    discriminatorColumn: undefined,
    treeLevelColumn: undefined,
    nestedSetLeftColumn: undefined,
    nestedSetRightColumn: undefined,
    materializedPathColumn: undefined,
    objectIdColumn: undefined,
    propertiesMap: {
      release: 'release',
      views: 'views',
      description: 'description',
      location: 'location',
      copyright: 'copyright',
      director: 'director',
      id: 'id',
      name: 'name',
      public: 'public',
      keys: 'keys',
      groups: 'groups',
      exports: 'exports',
      thumbnails: 'thumbnails'
    }
  },
  inverseSidePropertyPath: 'keys',
  inverseRelation: RelationMetadata {
    isTreeParent: false,
    isTreeChildren: false,
    isPrimary: false,
    isLazy: false,
    isEager: false,
    persistenceEnabled: true,
    isCascadeInsert: false,
    isCascadeUpdate: false,
    isCascadeRemove: false,
    isNullable: true,
    isOwning: true,
    isOneToOne: false,
    isOneToOneOwner: false,
    isWithJoinColumn: false,
    isOneToOneNotOwner: false,
    isOneToMany: false,
    isManyToOne: false,
    isManyToMany: true,
    isManyToManyOwner: true,
    isManyToManyNotOwner: false,
    foreignKeys: [ [ForeignKeyMetadata], [ForeignKeyMetadata] ],
    joinColumns: [ [ColumnMetadata] ],
    inverseJoinColumns: [ [ColumnMetadata] ],
    entityMetadata: EntityMetadata {
      childEntityMetadatas: [],
      inheritanceTree: [Array],
      tableType: 'regular',
      synchronize: true,
      hasNonNullableRelations: false,
      isJunction: false,
      isClosureJunction: false,
      hasMultiplePrimaryKeys: false,
      hasUUIDGeneratedColumns: true,
      ownColumns: [Array],
      columns: [Array],
      ancestorColumns: [],
      descendantColumns: [],
      nonVirtualColumns: [Array],
      ownerColumns: [],
      inverseColumns: [],
      generatedColumns: [Array],
      primaryColumns: [Array],
      ownRelations: [Array],
      relations: [Array],
      eagerRelations: [],
      lazyRelations: [],
      oneToOneRelations: [],
      ownerOneToOneRelations: [],
      oneToManyRelations: [Array],
      manyToOneRelations: [],
      manyToManyRelations: [Array],
      ownerManyToManyRelations: [Array],
      relationsWithJoinColumns: [],
      relationIds: [],
      relationCounts: [],
      foreignKeys: [],
      embeddeds: [],
      allEmbeddeds: [],
      ownIndices: [],
      indices: [],
      uniques: [],
      ownUniques: [],
      checks: [],
      exclusions: [],
      ownListeners: [],
      listeners: [],
      afterLoadListeners: [],
      beforeInsertListeners: [],
      afterInsertListeners: [],
      beforeUpdateListeners: [],
      afterUpdateListeners: [],
      beforeRemoveListeners: [],
      afterRemoveListeners: [],
      connection: [Connection],
      inheritancePattern: undefined,
      treeType: undefined,
      parentClosureEntityMetadata: undefined,
      tableMetadataArgs: [Object],
      target: [Function: Film],
      expression: undefined,
      engine: undefined,
      database: undefined,
      schema: 'glacier',
      givenTableName: undefined,
      targetName: 'Film',
      tableNameWithoutPrefix: 'film',
      tableName: 'film',
      name: 'Film',
      tablePath: 'glacier.film',
      schemaPath: 'glacier',
      orderBy: undefined,
      discriminatorValue: 'Film',
      treeParentRelation: undefined,
      treeChildrenRelation: undefined,
      createDateColumn: undefined,
      updateDateColumn: undefined,
      versionColumn: undefined,
      discriminatorColumn: undefined,
      treeLevelColumn: undefined,
      nestedSetLeftColumn: undefined,
      nestedSetRightColumn: undefined,
      materializedPathColumn: undefined,
      objectIdColumn: undefined,
      propertiesMap: [Object]
    },
    embeddedMetadata: undefined,
    target: [Function: Film],
    propertyName: 'keys',
    relationType: 'many-to-many',
    onDelete: undefined,
    onUpdate: undefined,
    deferrable: undefined,
    type: [Function: Key],
    propertyPath: 'keys',
    inverseEntityMetadata: EntityMetadata {
      childEntityMetadatas: [],
      inheritanceTree: [Array],
      tableType: 'regular',
      synchronize: true,
      hasNonNullableRelations: false,
      isJunction: false,
      isClosureJunction: false,
      hasMultiplePrimaryKeys: false,
      hasUUIDGeneratedColumns: true,
      ownColumns: [Array],
      columns: [Array],
      ancestorColumns: [],
      descendantColumns: [],
      nonVirtualColumns: [Array],
      ownerColumns: [],
      inverseColumns: [],
      generatedColumns: [Array],
      primaryColumns: [Array],
      ownRelations: [Array],
      relations: [Array],
      eagerRelations: [],
      lazyRelations: [],
      oneToOneRelations: [],
      ownerOneToOneRelations: [],
      oneToManyRelations: [],
      manyToOneRelations: [],
      manyToManyRelations: [Array],
      ownerManyToManyRelations: [],
      relationsWithJoinColumns: [],
      relationIds: [],
      relationCounts: [],
      foreignKeys: [],
      embeddeds: [],
      allEmbeddeds: [],
      ownIndices: [],
      indices: [],
      uniques: [Array],
      ownUniques: [Array],
      checks: [],
      exclusions: [],
      ownListeners: [],
      listeners: [],
      afterLoadListeners: [],
      beforeInsertListeners: [],
      afterInsertListeners: [],
      beforeUpdateListeners: [],
      afterUpdateListeners: [],
      beforeRemoveListeners: [],
      afterRemoveListeners: [],
      connection: [Connection],
      inheritancePattern: undefined,
      treeType: undefined,
      parentClosureEntityMetadata: undefined,
      tableMetadataArgs: [Object],
      target: [Function: Key],
      expression: undefined,
      engine: undefined,
      database: undefined,
      schema: 'glacier',
      givenTableName: undefined,
      targetName: 'Key',
      tableNameWithoutPrefix: 'key',
      tableName: 'key',
      name: 'Key',
      tablePath: 'glacier.key',
      schemaPath: 'glacier',
      orderBy: undefined,
      discriminatorValue: 'Key',
      treeParentRelation: undefined,
      treeChildrenRelation: undefined,
      createDateColumn: undefined,
      updateDateColumn: undefined,
      versionColumn: undefined,
      discriminatorColumn: undefined,
      treeLevelColumn: undefined,
      nestedSetLeftColumn: undefined,
      nestedSetRightColumn: undefined,
      materializedPathColumn: undefined,
      objectIdColumn: undefined,
      propertiesMap: [Object]
    },
    inverseSidePropertyPath: '',
    inverseRelation: undefined,
    junctionEntityMetadata: EntityMetadata {
      childEntityMetadatas: [],
      inheritanceTree: [],
      tableType: 'junction',
      synchronize: true,
      hasNonNullableRelations: false,
      isJunction: true,
      isClosureJunction: false,
      hasMultiplePrimaryKeys: true,
      hasUUIDGeneratedColumns: false,
      ownColumns: [Array],
      columns: [Array],
      ancestorColumns: [],
      descendantColumns: [],
      nonVirtualColumns: [],
      ownerColumns: [Array],
      inverseColumns: [Array],
      generatedColumns: [],
      primaryColumns: [Array],
      ownRelations: [],
      relations: [],
      eagerRelations: [],
      lazyRelations: [],
      oneToOneRelations: [],
      ownerOneToOneRelations: [],
      oneToManyRelations: [],
      manyToOneRelations: [],
      manyToManyRelations: [],
      ownerManyToManyRelations: [],
      relationsWithJoinColumns: [],
      relationIds: [],
      relationCounts: [],
      foreignKeys: [Array],
      embeddeds: [],
      allEmbeddeds: [],
      ownIndices: [Array],
      indices: [Array],
      uniques: [],
      ownUniques: [],
      checks: [],
      exclusions: [],
      ownListeners: [],
      listeners: [],
      afterLoadListeners: [],
      beforeInsertListeners: [],
      afterInsertListeners: [],
      beforeUpdateListeners: [],
      afterUpdateListeners: [],
      beforeRemoveListeners: [],
      afterRemoveListeners: [],
      connection: [Connection],
      inheritancePattern: undefined,
      treeType: undefined,
      parentClosureEntityMetadata: undefined,
      tableMetadataArgs: [Object],
      target: 'film_keys',
      expression: undefined,
      engine: undefined,
      database: undefined,
      schema: 'glacier',
      givenTableName: 'film_keys',
      targetName: '',
      tableNameWithoutPrefix: 'film_keys',
      tableName: 'film_keys',
      name: 'film_keys',
      tablePath: 'glacier.film_keys',
      schemaPath: 'glacier',
      orderBy: undefined,
      treeParentRelation: undefined,
      treeChildrenRelation: undefined,
      createDateColumn: undefined,
      updateDateColumn: undefined,
      versionColumn: undefined,
      discriminatorColumn: undefined,
      treeLevelColumn: undefined,
      nestedSetLeftColumn: undefined,
      nestedSetRightColumn: undefined,
      materializedPathColumn: undefined,
      objectIdColumn: undefined,
      propertiesMap: [Object]
    },
    joinTableName: 'film_keys'
  }
}"

Edit 2019-10-25: Fixed link to point to a specific commit line number, not master branch

It is a serious problem because if I add @JoinTable decorator on both sides, insert statements are spoiled. With @JoinTable decorator only on one side, I can start query only from one entity and relation is not bidirectional anymore. Could you please refer to this issue? Thanks.

right, @JoinTable must be only from one side of relation. Your problem I guess is that you are using @JoinTable wrongly. Docs clearly state you to use referenceColumnName. I don’t see it in your code example.

I had exactly the same problem.

This is how it works for me:

First side of the relationship, Product Entity

  @ManyToMany(() => Showcase, (showcase) => showcase.products)
  @JoinTable()
  showcases: Showcase[];

Second side of the relationship, Showcase Entity

  @ManyToMany(() => Product, (product) => product.showcases )
  products: product[];

Make sure you do not forget both inverseSide functions (showcase) => showcase.products and (product) => product.showcases. Forgetting one of those caused the problem for me.

This did the trick for me, thanks!