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

时间:2019-11-28 10:53:25

标签: 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) => token.user)
public token: Token;
// 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;

这是我将当前数据保存到数据库中的方式。

private async savePayload(tokenDto: CreateTokenDto) {
    const token = this.tokenRepository.create(tokenDto);
    return await this.tokenRepository.save(token);
}

当我第一次将令牌保存到数据库时,所有令牌都被保存。

第二次保存时出现错误。

  

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'

经过一些实验,我注意到当指定令​​牌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_ENTRY:密钥“ REL_d417e5d35f2434afc4bd48cb4d”的重复条目“ 36”

我搜索并找到了一些示例。

1)TypeORM upsert - create if not exist

2)https://github.com/typeorm/typeorm/issues/3342

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

enter image description here

可以选择什么,为什么我的令牌没有更新?

3 个答案:

答案 0 :(得分:1)

整个问题是Repository<T>.save()函数行为的结果。

根据the docssave()函数具有以下行为:

  

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

但是,如果实体内部没有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();

也许,您的另一选择是使userId字段成为表的主键。这将解决save()函数的upsert问题。如您所述,userId字段是一个索引,并且也是唯一的。因此,您可以轻松地使其成为主要领域。

这可以通过修改您的实体,删除@PrimaryGeneratedId并将userId设置为@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;

希望有帮助:)

答案 1 :(得分:0)

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

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

处理插入的重复项

如果您尝试为主键(或唯一索引)插入重复的值,则始终会出现该错误。有两种解决方法:插入之前检查并进行更新(如果可能已更改)或什么都不做。

答案 2 :(得分:0)

您可以使用 .save 进行更新和插入或检查是否存在然后 .update 否则 .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,
            };
          }
        }
      }
相关问题