본문 바로가기

Back-End/QueryDSL

JPQL을 QueryDSL로 바꿔보자!

주어진 JQPL

@Query("SELECT t FROM Todo t " +
            "LEFT JOIN t.user " +
            "WHERE t.id = :todoId")
Optional<Todo> findByIdWithUser(@Param("todoId") Long todoId);

JPQL 코드 상세 설명

@Query("SELECT t FROM Todo t")

  • SELECT t : Todo 엔티티의 인스턴스를 조회한다.
  • FROM Todo t : JPA 엔티티 Todo를 기준으로 조회하며, t는 엔티티의 별칭 이다.

LEFT JOIN t.user

  • LEFT JOIN : Todo와 연관된 User 데이터를 조인한다. Todo에 연관된 User가 없더라도 Todo는 항상 반환된다.
  • t.user : Todo 엔티티의 user 필드
    • 이 필드는 Todo 엔티티에서 @ManyToOne으로 매핑된 User 엔티티와의 관계를 나타냄

WHERE t.id = :todoId

  • WHERE : 특정 조건으로 결과를 필터링한다.
  • t.id = :todoId : Todo의 id 필드가 파라미터 todoId와 일치하는 레코드만 가져온다.
  • :todoId : 메서드의 @Param("todoId")으로 전달된 파라미터 값.

이제 QueryDSL로 변환해보자!

public Optional<Todo> findByIdWithUser(Long todoId) {
    QTodo todo = QTodo.todo; // QTodo는 Todo 엔티티의 QueryDSL 타입
    QUser user = QUser.user; // QUser는 User 엔티티의 QueryDSL 타입

    // QueryDSL로 JPQL 변환
    Todo result = queryFactory
            .selectFrom(todo)       // Todo 엔티티를 기준으로 조회
            .leftJoin(todo.user, user).fetchJoin()    // Todo와 User를 LEFT JOIN
            .where(todo.id.eq(todoId))               // 조건: Todo의 id가 todoId와 일치
            .fetchOne();                             // 단일 결과 조회

    return Optional.ofNullable(result);              // 결과를 Optional로 반환
}

QueryDsl 코드 상세 해석

QTodo todo = QTodo.todo;
QUser user = QUser.user;
  • QTodo : Todo 엔티티의 QueryDSL Q-Type 클래스
    • Todo 엔티티를 QueryDSL에서 사용할 수 있도록 생성된 클래스
  • QUser : User 엔티티의 QueryDSL Q-Type 클래스
    • User 엔티티를 QueryDSL에서 사용할 수 있도록 생성된 클래스
  • QueryDSL 플러그인 빌드 시 자동으로 생성
queryFactory.selectFrom(todo)
  • QueryDSL의 selectFromJPQL의 SELECT t FROM t에 해당한다.
  • todo는 조회할 기준이 되는 Todo엔티티의 Q-Type 객체이다.
.leftJoin(todo.user, user).fetchJoin()
  • leftJoin(todo.user, user)
    • Todo 엔티티의 user 필드(연관관계)와 User 엔티티를 조인
    • SQL의 LEFT JOIN에 해당하며 Todo에 매핑된 User를 가져온다
  • fetchJoin()
    • 조인된 연관 엔티티를 즉시 로드(Eager Fetch)한다.
    • 기본적으로 JPA는 Lazy Loading을 사용하여 연관된 엔티티를 필요할 때만 로드한다. fetchJoin()을 사용하면 즉시 로드로 변경된다.
.where(todo.id.eq(todoId))
  • 조건추가
    • todo.id는 Todo 엔티티의 id 필드이다.
    • eq(todoId)는 id가 파라미터로 전달된 todoId와 같은지 비교한다.
.fetchOne()
  • QueryDSL에서 단일 결과를 조회하는 메서드
  • 결과가 없으면 null 반환
  • 결과가 여러 개면 : NonUniqueResultException 예외 발생
  • 이 메서드는 항상 단일 결과만 반환되어야 하는 상황에서 사용

'Back-End > QueryDSL' 카테고리의 다른 글

Spring Data Jpa와 QueryDSL  (0) 2025.01.17
QueryDSL 중급 문법  (0) 2025.01.17
QueryDsl 기본 문법  (1) 2024.12.31
QueryDsl 3.x 설정  (0) 2024.12.29