Typeorm 如何更新实体(如果存在)或创建实体(如果不存在)

Typeorm 如何更新实体(如果存在)或创建实体(如果不存在),typeorm,Typeorm,这里是我的实体 // 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) =>

这里是我的实体

// 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;
这就是我在数据库中保存当前数据的方式

private async savePayload(tokenDto: CreateTokenDto) {
    const token = this.tokenRepository.create(tokenDto);
    return await this.tokenRepository.save(token);
}
当我第一次将令牌保存到数据库时,所有令牌都被保存

当我第二次保存时,我得到一个错误

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);
}
ER_DUP_条目:键“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'
经过一些实验,我注意到当我指定令牌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);
}
但是如果我没有指明令牌的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);
}
ER_DUP_条目:键“REL_d417e5d35f2434afc4bd48cb4d”的重复条目“36”

我搜索并找到了一些例子

一,

二,

他们说该值必须是主键或唯一值。但是我的userId字段是一个索引,也是唯一的


有哪些选项,为什么我的令牌没有更新?

这并不是说表中已经有一个重复的条目,而是说已经有一个条目具有主键的该值,并且出于这个原因拒绝插入第二个条目

您将找到一个匹配的行,并且出现错误时的代码正试图插入第二行

在插入时处理重复项:


如果您尝试为主键或唯一索引插入重复的值,则始终会出现该错误。有两种解决方法:在插入之前检查,如果某些内容可能已更改,则进行更新,或者不执行任何操作。

并不是说表中已经存在重复条目,这意味着其中已经有一个条目具有主键的该值,并且出于这个原因拒绝插入第二个条目

您将找到一个匹配的行,并且出现错误时的代码正试图插入第二行

在插入时处理重复项:


如果您尝试为主键或唯一索引插入重复的值,则始终会出现该错误。有两种解决方法:在插入之前进行检查,如果某些内容可能已更改,则执行更新,或者不执行任何操作。

整个问题都是Repository.save函数行为的结果

根据,保存功能具有以下行为:

在数据库中保存所有给定的实体。如果数据库中不存在实体,则插入,否则更新

但是,如果实体中没有id字段(没有PrimaryKey),则save方法假定该实体在数据库中不存在,并继续创建一个新实体,而不是更新现有实体。这就是为什么在实体中定义id字段时它会起作用

考虑到这一点,保存方法似乎不适合您的情况。您需要使用TypeORM的查询生成器编写自定义查询。这个自定义查询将非常接近您在问题中使用原始SQL编写的查询

您可以这样编写免责声明:我根本没有测试过代码!:

常量值={ uuid:'34344344344444', 用户ID:36 } 等待连接。createQueryBuilder 插入 .代币 .valuespost2 .onConflict`userId DO更新集UUID=:UUID` .setParametertitle,values.uuid 处决 也许,您的另一个选择是使userId字段成为表的主键。这将通过save函数解决upsert问题。正如您所描述的,userId字段是一个索引,也是唯一的。因此,您可以轻松地将其作为主字段

这可以通过修改实体、删除@PrimaryGenerateId并将用户ID设置为@PrimaryColumn来实现:

@列{type:'varchar',可为空:false} 公共uuid:string; @主柱 public userId:number; @OneToOne=>User,User:User=>User.hash,{cascade:['insert','remove']} @JoinColumn{name:'userId'} 公共用户:用户;
希望能有所帮助:

整个问题都是Repository.save函数行为的结果

根据,保存功能具有以下行为:

在数据库中保存所有给定的实体。如果数据库中不存在实体,则插入,否则更新

但是,如果实体中没有id字段(没有PrimaryKey),则save方法假定该实体在数据库中不存在,并继续创建一个新实体,而不是更新现有实体。这就是为什么在实体中定义id字段时它会起作用

考虑到这一点,保存方法似乎不适合您的情况。您需要使用TypeORM的查询生成器编写自定义查询。这个自定义查询将非常接近您在问题中使用raw S编写的查询 QL

您可以这样编写免责声明:我根本没有测试过代码!:

常量值={ uuid:'34344344344444', 用户ID:36 } 等待连接。createQueryBuilder 插入 .代币 .valuespost2 .onConflict`userId DO更新集UUID=:UUID` .setParametertitle,values.uuid 处决 也许,您的另一个选择是使userId字段成为表的主键。这将通过save函数解决upsert问题。正如您所描述的,userId字段是一个索引,也是唯一的。因此,您可以轻松地将其作为主字段

这可以通过修改实体、删除@PrimaryGenerateId并将用户ID设置为@PrimaryColumn来实现:

@列{type:'varchar',可为空:false} 公共uuid:string; @主柱 public userId:number; @OneToOne=>User,User:User=>User.hash,{cascade:['insert','remove']} @JoinColumn{name:'userId'} 公共用户:用户; 希望有帮助:

您可以使用。保存更新和插入,或者检查是否存在。更新其他。保存 例

您可以同时使用.save进行更新和插入,或者检查是否存在.update else.save 例


是的,第二个选项与我预期的一样有效。这是最完整的答案。谢谢,第二个选项如我所料有效。这是最完整的答案。谢谢
async CreateNewRole(data: any): Promise<Role | any> {
        try {
          const entity = await this.roleRepository.create(data);
          const role = await this.roleRepository.save(entity);
          this.trackingService.create(data.user);
          return {
            success: true,
            role,
          };
        } catch (e) {
          //  code == 23505 means duplication key
          if (parseInt(e.code) === 23505) {
            console.log('error : ', e.detail);
            return {
              success: false,
              message: ROLE_ERROR_MESSAGES.ROLE_IS_FOUND,
            };
          } else {
            return {
              success: false,
            };
          }
        }
      }
    
      async UpdateRole(data: any, id: number): Promise<Role | any> {
        try {
          await this.roleRepository.update(id, { ...data.payload });
          this.trackingService.create(data.user);
          // todo this need to be refactored !!
          // return back the updated entity
          const role = await this.roleRepository.find({ id });
          console.log('role updated ', role);
          return {
            role,
            success: true,
          };
        } catch (e) {
          if (parseInt(e.code) === 23505) {
            console.log('error : ', e.detail);
            return {
              success: false,
              message: ROLE_ERROR_MESSAGES.ROLE_IS_FOUND,
            };
          } else {
            return {
              success: false,
            };
          }
        }
      }