NestJS TypeOrm transaction save오류

권태형·2023년 4월 29일
0

bnb Back-Server Project

목록 보기
5/31

트랜잭션을 사용해보기 위해서 이것저것 포스팅과 공식문서를 참고하면서 로직을 짯는데 서버를 실행할 때 아래와 같은 에러가 발생했다.

"Cannot save, given value must be instance of entity class, instead object literal is given. Or you must specify an entity target to method call."

위 오류는 객체 리터럴(object literal: 중괄호({})로 둘러싸인 key-value 쌍으로 이루어진 객체)이 아닌 엔티티 클래스의 인스턴스를 저장해야 한다는 말인데, 내 코드는 원래 있던 코드에서 트랜잭션을 위해 살짝 변형한 코드여서 그런지 save()함수에 객체리터럴로 인자를 전달해 주었었다.

//기존코드
  async saveUserInfo(userInfo: SignUpDto): Promise<SignUpDto> {
    await this.transformPassword(userInfo);
    return await this.userRepository.save(userInfo); //<< save할때 entity가 아닌 userInfo의 객체리터럴을 사용
  }

  async transformPassword(userDto: SignUpDto): Promise<void> {
    userDto.password = await bcrypt.hash(userDto.password, 10);
  }
  
//transaction사용 연습을 위한 변경코드
  async saveUserInfo(userInfo: SignUpDto): Promise<SignUpDto> {
    // 주입한 dataSource객체로 QueryRunner생성
    const queryRunner = this.dataSource.createQueryRunner();
    //QueryRunner로 DB연결
    await queryRunner.connect();
    //트랜잭션 시작
    await queryRunner.startTransaction();
    try {
      await this.transformPassword(userInfo);
      const result = await queryRunner.manager.save(userInfo);//<< userInfo의 객체리터럴을 그대로 사용
      //트랜잭션 성공 후 적용
      await queryRunner.commitTransaction();
      return result;
    } catch (err) {
      console.error(err);
      //트랜잭션중 실패하면 롤백
      await queryRunner.rollbackTransaction();
      throw new HttpException('회원가입 트랜잭션 롤백 에러', 500);
    } finally {
      //트랜잭션 완료 후 연결끊기
      await queryRunner.release();
    }

    // return await this.userRepository.save(userInfo);
  }

위와 같은 에러를 해결하기 위한 방법에 대해서 알아보니 여러가지가 존재했다.

  1. 엔티티 클래스의 인스턴스를 생성한 후, 해당 인스턴스를 저장하는 방법
const entity = new Entity();
entity.property = value;
await entityManager.save(entity);
  1. 엔티티 클래스의 create() 메서드를 사용하여 객체 리터럴(object literal)을 엔티티 클래스의 인스턴스로 변환한 후, 해당 인스턴스를 저장하는 방법
const entity = Entity.create({ property: value });
await entityManager.save(entity);
  1. @Entity() 데코레이터에서 target 옵션을 지정하여, 해당 엔티티를 명시적으로 지정하는 방법
@Entity({ target: Entity })
class Entity {
  // ...
}

가장 처음 이미지와 같이 에러를 반출하는 것으로 보아서 트랜잭션은 잘 동작하는것 같고, 따라서 위의 첫번째 방법을 통해 이를 해결해 주니 정상동작하는 것을 확인할 수 있었다.

      const user = new User();
      user.email = userInfo.email;
      user.nickname = userInfo.nickname;
      user.password = userInfo.password;

      const result = await queryRunner.manager.save(user);

profile
22년 12월 개발을 시작한 신입 개발자 ‘권태형’입니다. 포스팅 하나하나 내가 다시보기 위해 쓰는 것이지만, 다른 분들에게도 도움이 되었으면 좋겠습니다. 💯컬러폰트가 잘 안보이실 경우 🌙다크모드를 이용해주세요.😀 지적과 참견은 언제나 환영합니다. 많은 댓글 부탁드립니다.

0개의 댓글