typeorm / typeorm

ORM for TypeScript and JavaScript. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, SAP Hana, WebSQL databases. Works in NodeJS, Browser, Ionic, Cordova and Electron platforms.
http://typeorm.io
MIT License
34.23k stars 6.31k forks source link

Duplicate junction tables created for ManyToMany relation with custom junctional table name #10643

Open phoenisx opened 9 months ago

phoenisx commented 9 months ago

Issue description

Duplicate junction tables created for ManyToMany relation with custom junctional table name

Expected Behavior

The only Junction table that should be created should be the one provided by @JoinTable({ name: 'name' }) relation decorator.

Actual Behavior

When I use @JoinTable with a custom name, TypeORM creates two Junction tables. One from its own (default), and one from the name I provided.

Steps to reproduce

Create the following Entities with relations as described below:

@Entity({ name: "foo_feature" })
export class FooFeature {
   @PrimaryGeneratedColumn('identity')
   id: number;
}

@Entity({ name: "foo" })
export class Foo {
   @PrimaryGeneratedColumn('identity')
   id: number;

   @ManyToMany(() => FooFeature)
   @JoinTable({
      name: "foo_included_features",
      joinColumn: {
         name: "foo",
         referencedColumnName: "id",
      },
      inverseJoinColumn: {
         name: "foo_feature",
         referencedColumnName: "id",
      },
   })
   included: typeorm.Relation<FooFeature[]>;
}

In When synchronized, or even when generating migration file, I get the two instances of Create Table, as described below:

query: CREATE TABLE "foo_included_features" ("foo" integer NOT NULL, "foo_feature" integer NOT NULL, CONSTRAINT "PK_abcd" PRIMARY KEY ("foo", "foo_feature"))
query: CREATE INDEX "IDX_abcd1" ON "foo_included_features" ("foo")
query: CREATE INDEX "IDX_abcd2" ON "foo_included_features" ("foo_feature")
query: CREATE TABLE "foo_included_foo_feature" ("foo_id" integer NOT NULL, "foo_feature_id" integer NOT NULL, CONSTRAINT "PK_xyz" PRIMARY KEY ("foo_id", "foo_feature_id"))
query: CREATE INDEX "IDX_xyz1" ON "foo_included_foo_feature" ("foo_id")
query: CREATE INDEX "IDX_xyz2" ON "foo_included_foo_feature" ("foo_feature_id")

NOo sure why foo_included_foo_feature is getting created, even though I have named my Junction table using @JoinTable.

My Environment

Dependency Version
Operating System Pop!_OS 22.04 LTS x86_64
Node.js version v20.9.0
Typescript version v5.1.6
TypeORM version v0.3.17

Additional Context

No response

Relevant Database Driver(s)

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

Yes, I have the time, but I don't know how to start. I would need guidance.

ragrag commented 2 weeks ago

typeorm always creates junction tables with the name you provide in JoinTable.name, and since this name is different from the entity FooFeature you defined, both of them are created.

You can either make both FooFeature and JoinTable have similar names, or u can omit creating the FooFeature manually and use the one typeorm creates

@Entity({ name: "foo_feature" }) // <- table created with name foo_feature
export class FooFeature {
   @PrimaryGeneratedColumn('identity')
   id: number;
}

@Entity({ name: "foo" })
export class Foo {
   @PrimaryGeneratedColumn('identity')
   id: number;

   @ManyToMany(() => FooFeature)
   @JoinTable({
      name: "foo_included_features", // <- typeorm uses this to create a table
      joinColumn: {
         name: "foo",
         referencedColumnName: "id",
      },
      inverseJoinColumn: {
         name: "foo_feature",
         referencedColumnName: "id",
      },
   })
   included: typeorm.Relation<FooFeature[]>;
}