Reputation: 366
Let's say I have a simple TypeORM entity like this:
import { Entity, PrimaryGeneratorColumn, Column } from 'typeorm';
@Entity()
export class Employee {
@PrimaryGeneratedColumn()
id: number;
@Column()
Name: string;
}
It all works fine as long as I do not touch database manually. If I enter a record manually, the Entity will not be able to check the last current id
from the table and throws error duplicate key value violates unique constraint
.
For example:
Employee Entity
creates two records by itself.id 2
id 3
Employee Entity
runs, it does not = create another record, since it wants to use id 3
, but I added that manually already.duplicate key value violates unique constraint
Employee Entity
runs again, it works, because it tries to save another record under id 4
already which is available.So how can I ensure, that Employee Entity
checks the last id from the database and then saves the next record with incremental id
?
Thank you
Upvotes: 4
Views: 21548
Reputation: 359
In my case, I had wrongly defined a relationship. It was supposed to be @ManyToOne
, but I had @OneToOne
.
This makes sense because a OneToOne should have one instance for each entity, Therefore the sequence generator gives the same id for every tried insert, causing the error as it's not unique for subsequent saves. I think TypeORM should give a different error message, took me 2 days to figure out.
Upvotes: 1
Reputation: 744
In TypeORM the decorator @PrimaryGeneratedColumn()
creates a primary column which the value will be generated using a sequence. Every time you add a new record on the database it uses the nextval
of the sequence set for that column. Assuming you are using PostgreSQL (I believe for other databases it would be similar) you have an Employee table
CREATE TABLE public.Employee (
number serial NOT NULL,
nane varchar NULL
);
And because the decorator @PrimaryGeneratedColumn()
a sequence employee_id_seq
will also be created. You can check its latest value by running
select last_value from employee_id_seq;
When your application creates two records it uses the sequence to generate the new ids, changing the employee_id_seq
last_value
value. With two records in the database the new last_value will be updated to 2.
If you create a third record manually passing id = 3
INSERT INTO public.Employee (id, name) VALUES(3, 'new_name')
the sequence will not be used, and its last_value will be 2. Next time your application tries to insert a new record it executes an insert without passing the id, because it relies on the sequence to generate the value, like this
INSERT INTO public.Employee (name) VALUES('another_name');
or (not sure how TypeORM handles it exactly)
INSERT INTO public.Employee (id, name) VALUES(nextval('employee_id_seq', 'another_name')
The SQL above will use the last_value
from the sequence and add 1, resulting in 3 and a duplicate key violation
. So if you add a record manually you don't need set the id manually, you can run
INSERT INTO public.Employee (name) VALUES('name')
and the id will be auto-generated using the sequence.
Upvotes: 5