typeorm: .save() is throwing duplicate key value violates unique constraint on Postgresql
Issue Description
When trying to upsert an entity to a Postgresql DB, I get a QueryFailedError: duplicate key value violates unique constraint.
Expected Behavior
I currently have a simple case :
await this.save(user); // works 🎉
await this.save(user); // should upsert the user
Where the User entity is defined as such :
@Entity()
class User {
@PrimaryColumn("text")
id: string; // idem with a number
@Column("text")
name: string;
}
Actual Behavior
await this.save(user); // works 🎉
await this.save(user); // fails the second time ☹
with a QueryFailedError: duplicate key value violates unique constraint.
Steps to Reproduce
A simple typeorm + Postgresql stack should suffice
My Environment
I’m on a plain TS stack, nothing fancy atm.
Relevant Database Driver(s)
-
aurora-data-api -
aurora-data-api-pg -
better-sqlite3 -
cockroachdb -
cordova -
expo -
mongodb -
mysql -
nativescript -
oracle -
postgres -
react-native -
sap -
sqlite -
sqlite-abstract -
sqljs -
sqlserver
Are you willing to resolve this issue by submitting a Pull Request?
- Yes, I have the time, and I know how to start.
- Yes, I have the time, but I don’t know how to start. I would need guidance.
- No, I don’t have the time, although I believe I could do it if I had the time…
- No, I don’t have the time and I wouldn’t even know how to start.
About this issue
- Original URL
- State: closed
- Created 3 years ago
- Reactions: 18
- Comments: 36 (11 by maintainers)
Links to this issue
Commits related to this issue
- fix: fix entityManager.getId for custom join table getId currently returns undefined for an entity with composite primary key if primary key columns also foreign keys with lazy relations, for e.g., i... — committed to ranjan-purbey/typeorm by ranjan-purbey 2 years ago
- fix: fix entityManager.getId for custom join table getId currently returns undefined for an entity with composite primary key if primary key columns also foreign keys with lazy relations, for e.g., i... — committed to ranjan-purbey/typeorm by ranjan-purbey 2 years ago
- fix: fix entityManager.getId for custom join table getId currently returns undefined for an entity with composite primary key if primary key columns also foreign keys with lazy relations, for e.g., i... — committed to ranjan-purbey/typeorm by ranjan-purbey 2 years ago
- fix: fix entityManager.getId for custom join table getId currently returns undefined for an entity with composite primary key if primary key columns also foreign keys with lazy relations, for e.g., i... — committed to ranjan-purbey/typeorm by ranjan-purbey 2 years ago
- fix: fix entityManager.getId for custom join table (#8676) getId currently returns undefined for an entity with composite primary key if primary key columns also foreign keys with lazy relations, f... — committed to typeorm/typeorm by ranjan-purbey 2 years ago
Reproducible example:
Then try upserting records:
However if
UserCourseentity just has a composite PK but not the many-to-one relations withUserandCourseentities as follows:then in that case, upsert works as expected
And as @leric said, before
0.2.32both of the above cases were handled correctlySQL logs in v0.2.31:
SQL logs in v0.2.32 and above:
I just created this issue with a code example to reproduce: https://github.com/typeorm/typeorm/issues/8272
any updates?
I’m also encountering this issue, any ETA on a fix?
This issue is still happening with: nest-typeorm: 9.0.1 typeorm: ^0.3.10 MariaDB: 10.7.3
Its possible to use
insert()and.orUpdate(), but using the combination simply results in burning ids, and not upserting correctly.For one of the possible solutions you can use the article: https://www.kindacode.com/snippet/typeorm-upsert-update-if-exists-create-if-not-exists/
PS. Using the save() method only works when you provide ids.
The bug was introduced by https://github.com/typeorm/typeorm/commit/7fe723b23b74a4c81608a856a82b8aa85fe1b385#diff-d7ca1d76c1ec2ccba6afd5a97313e55e8c1cb0dcb8ce2cadc927fc9a6891c521L549-R549
On L549,
entity[this.relationMetadata!.propertyName]will be a promise for lazy-loaded relationships instead of actual related entity. This causes the value map to be undefined, which in turn causesEntityMetadata.prototype.compareEntitiesto return false, Due to thisSubjectDatabaseEntityLoader.prototype.loadsetssubject.databaseEntityLoadedtotruebutsubject.databaseEntityremainsundefined, which meanstrueis returned forsubject.mustBeInsertedrather than forsubject.mustBeUpdated, opposed to the expected behavior.Note that this will work as expected for non-lazy relationships