Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeOrm: Create a ManyToOne relationship using uuid data type for the keys instead of integer

I have a Typescript Nestjs project using TypeORM and a PostgreSQL database, and I have trouble defining many-to-one relationships, because TypeORM tries to create an ID field of type integer, whereas I'm using UUID fields. Is there a way to tell TypeORM to use a different data-type than integer?

Here's an example of an entity that's not working:

export class AgentKitsEntity implements Model {
  @PrimaryGeneratedColumn()
  @Generated('uuid')
  id: string;
}

@Entity({name: 'users'})
export class User extends AgentKitsEntity implements UserModel {
  @Column()
  username: string;

  @ManyToOne(type => View)
  @JoinColumn({name: 'view_id', referencedColumnName: 'id'})
  view: View;
}

This leads to the following error:

query failed: ALTER TABLE "users" ADD CONSTRAINT "FK_2ed8b186dce83a446f94ac9aae4" FOREIGN KEY ("view_id") REFERENCES "views"("id")
error: { error: foreign key constraint "FK_2ed8b186dce83a446f94ac9aae4" cannot be implemented
    at Connection.parseE (/home/jonathan/projects/agent-kits/api-data/node_modules/pg/lib/connection.js:554:11)
    at Connection.parseMessage (/home/jonathan/projects/agent-kits/api-data/node_modules/pg/lib/connection.js:379:19)
    at Socket.<anonymous> (/home/jonathan/projects/agent-kits/api-data/node_modules/pg/lib/connection.js:119:22)
    at emitOne (events.js:116:13)
    at Socket.emit (events.js:211:7)
    at addChunk (_stream_readable.js:263:12)
    at readableAddChunk (_stream_readable.js:250:11)
    at Socket.Readable.push (_stream_readable.js:208:10)
    at TCP.onread (net.js:601:20)
  name: 'error',
  length: 228,
  severity: 'ERROR',
  code: '42804',
  detail: 'Key columns "view_id" and "id" are of incompatible types: integer and uuid.',
  hint: undefined,
  position: undefined,
  internalPosition: undefined,
  internalQuery: undefined,
  where: undefined,
  schema: undefined,
  table: undefined,
  column: undefined,
  dataType: undefined,
  constraint: undefined,
  file: 'tablecmds.c',
  line: '6503',
  routine: 'ATAddForeignKeyConstraint' }

EDIT: Just to be clear, the issue isn't creating the UUID field for the primary key, that's working. The issue is that the table I'm referencing (in this example, "views"), uses a UUID primary key, so I need to use a UUID for the field referencing it as well ("views", in this example). TypeORM automatically creates the "view_id" field with an integer type, presumably because it assumes that primary key values will (should?) always be integers (which strikes me as a pretty crazy assumption).

It must be configurable somehow, no?

like image 547
jonneve Avatar asked Jan 02 '23 09:01

jonneve


1 Answers

I ended up finding the solution to this, and I'll post it here for future reference.

The following works for me:

export class AgentKitsEntity implements Model {
  @PrimaryGeneratedColumn('uuid')
  @Generated('uuid')
  id: string;
}

@Entity({name: 'users'})
export class User extends AgentKitsEntity implements UserModel {

  @Column()
  username: string;

  @ManyToOne(type => View, { nullable: true })
  @JoinColumn({name: 'view_id'})
  view: View;
}

The key difference that seems to have solved it is that I specified 'uuid' in the @PrimaryGeneratedColumn() decorator. This is surprising, as the fields actually were correctly created as UUID in the database, but it seems as though TypeORM assumes the key fields are integers unless you explicitly specify the type, even though it knows enough to figure out how to create the right data type for the field itself.

EDIT: On closer examination, it turns out that the @Generated('uuid') entity is redundant, and so the code for the base class above can be simplified to:

export class AgentKitsEntity implements Model {
  @PrimaryGeneratedColumn('uuid')
  id: string;
}
like image 154
jonneve Avatar answered Jan 05 '23 19:01

jonneve