Consider this entity:
// account.ts
import { Entity, PrimaryGeneratedColumn, PrimaryColumn, Column, BaseEntity, Index, CreateDateColumn, UpdateDateColumn, OneToOne, JoinColumn } from 'typeorm'
@Entity()
export class Account extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
@Column({ length: 50, unique: true })
@Index({ unique: true })
accountIdentifier: string
@Column({ nullable: true, length: 100 })
name?: string
}
To save a new account
or return an existing account
we have this working code:
const knownAccount = await Account.findOne({ accountIdentifier: token.oid })
if (knownAccount) return done(null, knownAccount, token)
const account = new Account()
account.accountIdentifier = token.oid
account.name = token.name
account.userName = (token as any).preferred_username
const newAccount = await account.save()
return done(null, newAccount, token)
In the docs it says:
save - Saves a given entity or array of entities. If the entity already exist in the database, it is updated. If the entity does not exist in the database, it is inserted. It saves all given entities in a single transaction (in the case of entity, manager is not transactional). Also supports partial updating since all undefined properties are skipped. Returns the saved entity/entities.
So we would expect this code to work and replace the previous code but it does not seem to update the row but rather complains about inserting a duplicate key:
const account = await Account.save({
accountIdentifier = token.oid,
name = token.name,
userName = (token as any).preferred_username,
})
return done(null, account, token)
The IDE does show it will update or insert but it does not update:
How is it possible to use the save
method correctly? So it adds an account if it doesn't exist and/or updates the account when it's already there.
Consider this entity:
// account.ts
import { Entity, PrimaryGeneratedColumn, PrimaryColumn, Column, BaseEntity, Index, CreateDateColumn, UpdateDateColumn, OneToOne, JoinColumn } from 'typeorm'
@Entity()
export class Account extends BaseEntity {
@PrimaryGeneratedColumn()
id: number
@Column({ length: 50, unique: true })
@Index({ unique: true })
accountIdentifier: string
@Column({ nullable: true, length: 100 })
name?: string
}
To save a new account
or return an existing account
we have this working code:
const knownAccount = await Account.findOne({ accountIdentifier: token.oid })
if (knownAccount) return done(null, knownAccount, token)
const account = new Account()
account.accountIdentifier = token.oid
account.name = token.name
account.userName = (token as any).preferred_username
const newAccount = await account.save()
return done(null, newAccount, token)
In the docs it says:
save - Saves a given entity or array of entities. If the entity already exist in the database, it is updated. If the entity does not exist in the database, it is inserted. It saves all given entities in a single transaction (in the case of entity, manager is not transactional). Also supports partial updating since all undefined properties are skipped. Returns the saved entity/entities.
So we would expect this code to work and replace the previous code but it does not seem to update the row but rather complains about inserting a duplicate key:
const account = await Account.save({
accountIdentifier = token.oid,
name = token.name,
userName = (token as any).preferred_username,
})
return done(null, account, token)
The IDE does show it will update or insert but it does not update:
How is it possible to use the save
method correctly? So it adds an account if it doesn't exist and/or updates the account when it's already there.
3 Answers
Reset to default 10If it can help people who face the same problem, i think that .save()
will perform an update in case the primary column (id in this case) is precised and exists in database. But be careful if the value of "id" is a string, i don't know why but somehow the save method won't perform the update, instead it will try to insert a new entity inside the database with the given id which may conduct to a constraint fail error (duplicate entry '' for key 'PRIMARY'
) if the id already exists, to avoid this simply typecast 'id' to integer.
When we use TypeORM .save
for an update it compares the IDs to decide whether to send CREATE or UPDATE request to DB.
In my case, the IDs were '123ce' and '123CE', so TypeORM decides to CREATE a new record. DB responds that it's already exists.
The way out is check out how your DB stores IDs, and to use appropriate method for an ID. For instance, .toUpperCase()
:
accountIdentifier = token.oid.toUpperCase(),
I spend a while later but in case it helps someone: In my case I have this entity
export class orders {
@AutoMap()
@PrimaryColumn({ type: 'bigint' })
id!: number;
}
When Typeorm tries to do the save() the format that the 'ID' field has in the table is of type string (the bigint type is saved as string type in the db), but the one that the entity has is of type interger, so it would be necessary for you to use another data type 'ID', cast it or in my case change the type to string:
export class orders {
@AutoMap()
@PrimaryColumn({ type: 'bigint' })
id!: string;
}
That should work.
.findOne()
and then do.save()
if it didn't' find an account. Example is the second code block in the question above. – DarkLite1 Commented Jan 21, 2021 at 9:15