본문 바로가기
Today I Learned 2024. 7. 24.

(24.07.24)[15주차] Sprint Data JPA Tuple 객체의 사용

JPQL을 통한 JPA를 쿼리 언어를 사용하면서 여러 테이블을 조인을 하다가 보면은 다양한 컬럼들의 값들을 골라서 사용을 하고 싶을 때가 있다.

 

즉 게시글 테이블에는 작성자 User의 ID만이 저장되어있지만, User 테이블과 JOIN을 해서 User 테이블에서 사용자ID가 아닌 이름이나 기타 정보를 가지고 있는  컬럼들을 골라서 가지고 올 수 있어

 

프로젝트에 있어서 조회 부분에 능동적으로 사용하기 위해서 Tuple 객체의 사용을 정리

 


 

Tuple 객체

  • JPQL은 SQL 처럼 Table 이 아닌 Entity(객체) 기준으로 작성하는 쿼리문으로 @Query Annotation을 사용해서 해당 쿼리를 컴파일시 체크를 할 수 있도록 할 수 있음
    • 따라서, 이러한 JPQL은 실제 SQL처럼 JOIN 문을 통해서 여러 엔터티 = 테이블을 합칠 수 있고, 여기서 발생한 DB에서 발생한 조인 테이블의 다중 컬럼들을 묶은 어떤 객체
  • DB의 ROW 값을 Tuple이라하는 그 값을 말하는 것

Object[] 를 사용안하는 이유

  • Tuple객체의 컬럼들은 이름을 지정해서 사용할 수 있고, Object는 컬럼 외에도 다른 Java 객체도 모두 포함하기 때문에 오류발생 가능성이 높음
  • 무조건 하나씩 인덱스 값을 빼올때마다 캐스팅을 해야하는데 이 과정에서 맞지 않을 경우, 오류가 당연히 발생하는 불편함이 존재

Tuple 객체 주요 메서드

get(String alias)

  • Tuple 객체에 있는 Column 이름을 넣어서 해당 Column을 Object 타입으로 반환
  • 어떤 특정 값을 구하려는 것이 아니라 해당 컬럼을 다른 Tuple 타입을 지원하는 데이터로 add 등을 통해 가공을 할 때 사용

get(int index)

  • 해당 인덱스의 Column을 Object 타입으로 반환 하는 메서드
    • 위의 get과 비슷한 메서드

get(int index, Class<T> type)

  • 해당 인덱스의 Column을 지정한 리터럴 타입으로 반환 하는 메서드
    • 가장 많이 활용할 수 있는 메서드

ex) String name = tuple.get(0, String.class);

getJavaType(String alias)

  • Class<T> type 으로 괄호안의 Column 어떤 타입인지 알 수 있는 메서드

getAlias(int index)

  • 해당 index의 Column 의 Alias 를 String 타입으로 알 수 있는 메서드

Tuple 활용하기

  • 실제 프로젝트에서 활용해보면서 어떻게 작동되는지 기록
// Repository
public interface CodeReviewCommentsRepository extends JpaRepository<CodeReviewComments, Long> {

  @Query("SELECT crc, u.name, COUNT(l) AS likes FROM CodeReviewComments crc " +
         "LEFT JOIN Users u ON crc.user.id = u.id " +
         "LEFT JOIN Likes l ON crc.id = l.codeReviewComment.id AND l.status = 'LIKED' " +
         "WHERE crc.codeReviews.id = :codeReviewsId AND crc.status = 'ACTIVE' " +
         "GROUP BY crc.id, u.name " +
         "ORDER BY crc.createdAt DESC")
  List<Tuple> findByCodeReviewIdWithDetails(Long codeReviewsId);
}

  • JPQL로 Likes 객체, User 객체, CodeReviewComments 객체 3가지 객체로 만들어진 DB의 테이블 JOIN
    • CodeReviewComments Column들 + User의 Name Column + Likes 객체 COUNT Column
List<Tuple> responseList = codeReviewCommentsRepository.findByCodeReviewIdWithDetails(
            codeReviewsId)
  • 사실상 JOIN 된 테이블은 Tuple이 순서대로 저장된 어떠한 List<Tuple> 됨
public class CodeReviewCommentsWithLikesResponseDto {

  private final Long id;
  private final String contents;
  private final String name;
  private final Long likes;
  private final LocalDateTime createdAt;
  private final LocalDateTime modifiedAt;

  public CodeReviewCommentsWithLikesResponseDto(Tuple tuple) {
    CodeReviewComments codeReviewComments = tuple.get(0, CodeReviewComments.class);
    String name = tuple.get(1, String.class);
    Long likes = tuple.get(2, Long.class);

    this.id = codeReviewComments.getId();
    this.contents = codeReviewComments.getContents();
    this.name = name;
    this.likes = likes;
    this.createdAt = codeReviewComments.getCreatedAt();
    this.modifiedAt = codeReviewComments.getModifiedAt();
  }
}

  • 따라서, 각 튜플의 Column 즉 Attribute 를 인덱스로 반환 타입을 지정하는 get 메서드를 활용이 가능
    • 위는 ResponseDto를 만들 수 있는 생성자에 사용된 예시