Есть ли способ, которым я могу получить доступ к сохраненным объектам в транзакции в TypeORM?

#postgresql #nestjs #typeorm

#postgresql #nestjs #typeorm

Вопрос:

Я использую Nest.js с помощью TypeORM и Postgres.

То, что я пытаюсь сделать, это создать и экземпляр моей User сущности. В нем есть Membership и File поля, которые также являются объектами. Они имеют отношение один к одному User , поэтому создаются при User создании. Если что-то пойдет не так, я хочу все откатить, поэтому я использую транзакцию.

Это то, что я делаю:

 async create(userProcessed: UserProcessed): Promise<UserResponse> {
    const response: UserResponse = {
      message: 'User not created',
      success: false,
      user: undefined,
    };
    const queryRunner = this.connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const membership = new Membership();
      membership.membershipState = userProcessed.membershipState;
      membership.membershipType = userProcessed.membershipType;
      const membershipSaved = await queryRunner.manager.save(membership);
      if (!membershipSaved) throw Error();

      const file = new File();
      file.weight = userProcessed.file.weight;
      file.height = userProcessed.file.height;
      const fileSaved = await queryRunner.manager.save(file);
      if (!fileSaved) throw Error(response.message);

      const user = new User();
      user.email = userProcessed.email;
      user.firstName = userProcessed.firstName;
      user.lastName = userProcessed.lastName;
      user.gender = userProcessed.gender;
      user.file = fileSaved;
      user.membership = membershipSaved;
      user.role = userProcessed.role;
      user.birthday = new Date(userProcessed.birthday);
      user.setPassword(userProcessed.password);

      const userSaved = await this.userRepository.save(user);
      console.log(userSaved);
      if (!userSaved) throw Error(response.message);

      response.success = true;
      response.message = 'User created';
      response.user = userSaved;

      await queryRunner.commitTransaction();
      return response;
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw Error(response.message);
    } finally {
      await queryRunner.release();
    }
  }
  

Проблема возникает при создании пользователя. Поскольку я использую транзакцию, ничего не сохраняется в БД, пока я не вызову await queryRunner.commitTransaction(); (как и должно быть). В результате membership и file , которые я пытаюсь использовать в качестве внешнего ключа, на самом деле не существует.

Есть ли способ, которым я могу решить эту проблему в той же транзакции?

Ответ №1:

Это было проще, чем я думал.

Я только что обнаружил, что могу установить { cascade: ['insert'] } @OneToOne аннотацию в User . При этом нет необходимости сохранять File или Membership раньше User , сохраняются при User сохранении.

В user.entity.ts :

   ...
  @OneToOne(type => Membership, { cascade: ['insert'] })
  @JoinColumn({ name: 'membership_id' })
  membership: Membership;

  @OneToOne(type => File, { cascade: ['insert'] })
  @JoinColumn({ name: 'file_id' })
  file: File;
  ...
  

В user.service.ts

   async create(userProcessed: UserProcessed): Promise<UserResponse> {
    const response: UserResponse = {
      message: 'User not created',
      success: false,
      user: undefined,
    };
    const queryRunner = this.connection.createQueryRunner();
    await queryRunner.connect();
    await queryRunner.startTransaction();
    try {
      const membership = new Membership();
      membership.membershipState = userProcessed.membershipState;
      membership.membershipType = userProcessed.membershipType;

      const file = new File();
      file.weight = userProcessed.file.weight;
      file.height = userProcessed.file.height;

      const user = new User();
      user.email = userProcessed.email;
      user.firstName = userProcessed.firstName;
      user.lastName = userProcessed.lastName;
      user.gender = userProcessed.gender;
      user.file = file;
      user.membership = membership;
      user.role = userProcessed.role;
      user.birthday = new Date(userProcessed.birthday);
      user.setPassword(userProcessed.password);

      const userSaved = await this.userRepository.save(user);
      console.log(userSaved);
      if (!userSaved) throw Error(response.message);

      response.success = true;
      response.message = 'User created';
      response.user = userSaved;

      await queryRunner.commitTransaction();
      return response;
    } catch (e) {
      await queryRunner.rollbackTransaction();
      throw Error(response.message);
    } finally {
      await queryRunner.release();
    }
  }
  

И с этим все работает как шарм!