这是我的实体。
// user
@PrimaryGeneratedColumn()
public id: number;
@Column({ type: 'varchar', nullable: false })
public email: string;
@Column({ type: 'varchar', nullable: false })
public password: string;
@OneToOne(() => Token, (token: Token) => token.user)
public token: Token;
Run Code Online (Sandbox Code Playgroud)
// token
@PrimaryGeneratedColumn()
public id: number;
@Column({ type: 'varchar', nullable: false })
public uuid: string;
@Column({ type: 'integer', nullable: false })
public userId: number;
@OneToOne(() => User, (user: User) => user.hash, { cascade: ['insert', 'remove'] })
@JoinColumn({ name: 'userId' })
public user: User;
Run Code Online (Sandbox Code Playgroud)
这就是我在我的数据库中保存当前的方式。
private async savePayload(tokenDto: CreateTokenDto) {
const token = this.tokenRepository.create(tokenDto);
return await this.tokenRepository.save(token);
}
Run Code Online (Sandbox Code Playgroud)
当我第一次将我的令牌保存到数据库时,所有这些都被保存了。
当我第二次保存时,出现错误。
ER_DUP_ENTRY:密钥“REL_d417e5d35f2434afc4bd48cb4d”的重复条目“36”
我阅读了有关 save 方法的文档。但为什么我得到错误,我无法理解。我希望记录会被更新。为什么我的令牌详细信息没有更新?
我了解如何使用 sql 执行此操作。
INSERT INTO "Tokens" (UUID, USERID)
VALUES ('d93ab036-768c-420a-98d6-2f80c79e6ae7', 36)
ON CONFLICT (USERID)
DO UPDATE SET UUID = 'd93ab036-768c-420a-98d6-2f80c79e6ae7',
USERID = 36'
Run Code Online (Sandbox Code Playgroud)
经过一些实验,我注意到当我指定令牌ID时,则保存或更新成功。
private async savePayload(tokenDto: CreateTokenDto) {
const a = {
id: 15,
uuid: '343443443444444444444444',
userId: 36,
};
const token = this.tokenRepository.create(a);
return await this.tokenRepository.save(token);
}
Run Code Online (Sandbox Code Playgroud)
但是如果我没有指明令牌的 id,我就会得到一个错误。
private async savePayload(tokenDto: CreateTokenDto) {
const a = {
// id: 15,
uuid: '343443443444444444444444',
userId: 36,
};
const token = this.tokenRepository.create(a);
return await this.tokenRepository.save(token);
}
Run Code Online (Sandbox Code Playgroud)
ER_DUP_ENTRY:密钥“REL_d417e5d35f2434afc4bd48cb4d”的重复条目“36”
我搜索并找到了一些例子。
2) https://github.com/typeorm/typeorm/issues/3342
他们说该值必须是主键或唯一值。但是我的 userId 字段是一个索引,而且也是唯一的。
可以有哪些选项,为什么我的令牌没有更新?
小智 7
整个问题是Repository<T>.save()函数行为的结果。
根据docs,该save()函数具有以下行为:
将所有给定的实体保存在数据库中。如果数据库中不存在实体,则插入,否则更新。
但是,如果没有id实体内部的字段(没有 PrimaryKey),该save()方法会假定该实体不存在于数据库中,并继续创建一个新实体而不是更新现有实体。所以这就是当您id在实体中定义字段时它起作用的原因。
考虑到这一点,该save()方法似乎不适用于您的情况。您需要使用 TypeORM 的查询构建器编写自定义查询。此自定义查询将非常接近您在问题中使用原始 SQL 编写的查询。
这就是您可以编写它的方式(免责声明:我根本没有测试过代码!):
const values = {
uuid: '343443443444444444444444',
userId: 36
}
await connection.createQueryBuilder()
.insert()
.into(Tokens)
.values(post2)
.onConflict(`("userId") DO UPDATE SET UUID = :uuid`)
.setParameter("title", values.uuid)
.execute();
Run Code Online (Sandbox Code Playgroud)
也许,您的另一种选择是将该userId字段设为表的主键。这将解决save()函数的 upsert 问题。正如您所描述的, userId 字段是一个索引,它也是唯一的。因此,您可以轻松地将其设为主要字段。
这可以通过修改您的实体,删除@PrimaryGeneratedId和使 userId a 来完成@PrimaryColumn:
@Column({ type: 'varchar', nullable: false })
public uuid: string;
@PrimaryColumn()
public userId: number;
@OneToOne(() => User, (user: User) => user.hash, { cascade: ['insert', 'remove'] })
@JoinColumn({ name: 'userId' })
public user: User;
Run Code Online (Sandbox Code Playgroud)
希望有帮助:)
| 归档时间: |
|
| 查看次数: |
11587 次 |
| 最近记录: |