웅글웅글: Nest 게시판 + 채팅 5. Repository: Spring Data JPA, QueryDsl vs. TypeORM

메밀·2024년 2월 20일
0

웅글웅글: NestJS

목록 보기
5/9

1. 오늘은 대충 무승부

Spring Boot와 NestJS의 Repository를 비교해볼 시간이다.
대충 DB와 상호작용하는 법을 비교해보겠다는 뜻이고, 다른 건 그놈이 그놈이라 SELECT 위주로 비교할 것이다.

오늘의 승부ㅋㅋㅋ를 요약하자면 다음과 같다.

TypeORM 압승

2. 데이터 가져오기

1) TypeORM 압승 🎉

TypeORM 하나로 다 된다.

Spring Boot 환경에서 1) 엔티티를 만들고, 2) 쿼리메소드를 사용하면서, 3) 복잡한 쿼리를 다루려면 다음과 같은 일들을 해야한다.

  • Spring Data JPA 의존성 추가
  • 엔티티 클래스 및 Repository 인터페이스 생성
  • QueryDsl 의존성 추가 및 초기 설정(대왕 복잡)
  • QueryDsl 인터페이스, 클래스 코드 작성...

정리해서 저 정도지 디테일하게는 Repository 클래스/인터페이스도 자꾸 늘어나고, QueryDsl을 나중에 도입한거면 설정이랑 씨름도 좀 해야하고, 기존 JPA용 리파지토리도 좀 만져줘야하고, gitignore도 수정해야하고, Qclass 잘 생기는지도 봐야한다.

문제는 이게 뭐 대단한 걸 만들고자 하는 게 아니라 '그냥 DB랑 소통하려면 이정도는...'이라는 점이다.

그런데 이 모든 작업들을 TypeORM 하나로 끝낼 수 있다는 게 정말 편리하다!

2) 쿼리메소드도 TypeORM 압승 🎉

TypeORM Repository의 기본적인 메소드는 다음과 같다.

메소드설명
save()엔티티 저장
remove(entity)엔티티 삭제
findOne()한 개 찾기
find()여러 개 찾기
count()개수 반환

사실 INSERT, UPDATE, DELETE는 JPA나 TypeORM이나 그놈이 그놈이다.

결국 비교해야할 건 SELECT 관련 메소드들인데, TypeORM에게 승리를 준 이유는 바로 FindOptions 때문이다.

- FindOptions

위 표의 하단 세 가지 메소드, 즉 SELECT 관련 메소드의 인자로는 PK나 FindOptions를 넘겨주면 된다.

엔터티를 조회할 때 사용되는 옵션 (인터페이스)
where, relations, order, skip(생략할 엔티티 개수), take(가져올 개수) 등이 있다.

사용 예시는 다음과 같다.

// 확인하지 않은 댓글 구하기
const unCheckedComments = await this.commentRepository.find({
      where: {
        board: {
          user: { userId } // 본인이 작성한 글
        },
        checked: false // 확인하지 않은 댓글만
      },
      order: {
        createdAt: "DESC"
      },
      relations: ["user", "board"]
    });

- 이거 꽤 편하다 ⭐️

예컨대 Spring Data JPA의 경우, User 엔티티의 PK가 userId고 (통상적 의미의) 아이디를 username이라고 저장한다고 가정했을 때, JPA Repository 인터페이스에 findByUsername이라는 메소드를 작성해줘야한다.

반면, TypeORM은 메소드 정의 없이 서비스 클래스에서 옵션 객체만 넘기면 돼서 편하다.

- Promise 반환

TypeORM 메소드는 기본적으로 모두 Promise를 반환한다.
await 잘 붙여야한다.

3) CreateQueryBuilder vs. QueryDsl

Spring 환경에서조금이라도 복잡한 쿼리가 필요하다면 QueryDsl 사용이 필수인데, TypeORM은 다른 의존성이 필요없다. 대충 JPA + QueryDsl 느낌이다.

// 인기글 조회
const populars = await this.boardRepository.createQueryBuilder("board")
      .leftJoinAndSelect("board.user", "user") // user: 연결된 엔티티의 별칭
      .leftJoinAndSelect("board.likes", "likes")
      .addSelect("COUNT(likes.likeId)", "likesCount")
      .groupBy("board.boardId")
      .orderBy("likesCount", "DESC")
      .take(5)
      .getMany();

심지어 작성법도 크게 다르지 않다.

- 잔잔하게 좋은 점: Expressions 어쩌구 안해도 됨

위 TypeORM 코드의 ORDER BY 부분을 QueryDsl로 작성한다면 대충 이런 모양이 될 것이다.

    .orderBy(Expressions.numberTemplate(Integer.class, "COUNT({0})", like.likeId).desc())

뭔가 늘 가독성이 떨어지는 느낌이었고, 사실 쓸 때마다 몰라서 구글링 엄청 한다.
TypeORM쪽이 직관적이라고 본다.

- 롬복아 고마워!

좀 의식의 흐름이긴한데 ㅋㅋㅋ NestJS에는 롬복같은 친구가 없다.
Builder 쓰려면 직접 구현해야한다😱

0개의 댓글