해결된 질문
작성
·
275
0
const qr = this.dataSource.createQueryRunner();
ERROR [ExceptionsHandler] Cannot read properties of undefined (reading 'createQueryRunner')
TypeError: Cannot read properties of undefined (reading 'createQueryRunner')
at TransactionInterceptor.intercept (C:\Users\Administrator\Desktop\cf_sns\src\common\interceptor\transaction.interceptor.ts:21:32)
이 에러가 떠서 postman으로 테스트를 진행하지 못하고있습니다.
dataSource도 typeorm에서 import 해서 사용했는데 컨트롤러에서 트랜잭션을 사용할때는 됐다가 인터셉터로 따로 빼서 사용하려고할 때 발생한 오류입니다.
답변 1
0
안녕하세요!
에러를 번역해보면 createQueryRunner를 undefined에 실행하려고하니 나는 에러네요.
즉, datasource가 undefined입니다.
정상적인 상황이라면 datasource가 undefined가 될 수 없습니다.
this.datasource가 왜 null인지 확인을 하셔야 할 것 같습니다.
interceptor로 따로 빼서 실행하려 할때 나는 에러라면 어떤 코드 변경이 있었는지, 실수한건 없는지 확인 해보셔야겠습니다.
도저히 모르겠다면 문제라고 생각되는 부분들을 더 넓게 캡쳐를 해주셔야합니다. 감사합니다!
감사합니다!
// posts.controller.ts import { Body, Controller, Post, UseGuards, UseInterceptors, } from '@nestjs/common'; import { QueryRunner as QR } from 'typeorm'; import { TransactionInterceptor } from 'src/common/interceptor/transaction.interceptor'; import { QueryRunner } from 'src/common/decorator/query-runner.decorator'; @Post() @UseGuards(AccessTokenGuard) @UseInterceptors(TransactionInterceptor) async postPosts( @User('id') userId: number, @Body() body: CreatePostDto, @QueryRunner() qr: QR, ) { const post = await this.postsService.createPost(userId, body, qr); // throw new InternalServerErrorException('TEST'); for (let i = 0; i < body.images.length; i++) { await this.postsImagesService.createPostImage( { post, order: i, path: body.images[i], type: ImageModelType.POST_IMAGE, }, qr, ); } return this.postsService.getPostById(post.id, qr); }
// transaction.interceptor.ts /* eslint-disable prettier/prettier */ import { CallHandler, ExecutionContext, InternalServerErrorException, NestInterceptor, } from '@nestjs/common'; import { Observable, catchError, tap } from 'rxjs'; import { DataSource } from 'typeorm'; export class TransactionInterceptor implements NestInterceptor { constructor(private readonly dataSource: DataSource) {} async intercept( context: ExecutionContext, next: CallHandler<any>, ): Promise<Observable<any>> { const req = context.switchToHttp().getRequest(); // 트랜잭션과 관련된 모든 쿼리를 담당할 // 쿼리 러너를 생성한다. const qr = this.dataSource.createQueryRunner(); // 쿼리 러너에 연결한다. await qr.connect(); // 쿼리 러너에서 트랜잭션을 시작한다. // 이 시점부터 같은 쿼리러너를 사용하면 // 트랜잭션 안에서 데이터베이스 액션을 실행할 수 있다. await qr.startTransaction(); req.queryRunner = qr; return next.handle().pipe( catchError(async (e) => { await qr.rollbackTransaction(); await qr.release(); throw new InternalServerErrorException(e.message); }), tap(async () => { await qr.commitTransaction(); await qr.release(); }), ); } }
해당 강의에서 사용된 코드 부분입니다.