QueryDSL 적용

박윤택·2022년 11월 10일
0

Spring

목록 보기
15/18

QueryDSL

QueryDSL을 사용하면 복잡한 쿼리를 Java로 표현가능하며 동적인 쿼리도 작성이 가능하다. 기존의 복잡한 쿼리들을 JPQL이나 native query로 작성하였는데 이번 프로젝트를 진행하면서 JPA와 QueryDSL을 적용하려 한다.


적용

build.gradle

buildscript {
	ext {
		queryDslVersion = "5.0.0"
	}
}

plugins {
	...
	id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
	...
}


dependencies {
	...
	implementation "com.querydsl:querydsl-jpa:${queryDslVersion}"
	implementation "com.querydsl:querydsl-apt:${queryDslVersion}"
	...
}

/*
 * queryDSL 설정 추가
 */
// querydsl에서 사용할 경로 설정
def querydslDir = "$buildDir/generated/querydsl"
// JPA 사용 여부와 사용할 경로를 설정
querydsl {
	jpa = true
	querydslSourcesDir = querydslDir
}
// build 시 사용할 sourceSet 추가
sourceSets {
	main.java.srcDir querydslDir
}
// querydsl 컴파일시 사용할 옵션 설정
compileQuerydsl{
	options.annotationProcessorPath = configurations.querydsl
}
// querydsl 이 compileClassPath 를 상속하도록 설정
configurations {
	compileOnly {
		extendsFrom annotationProcessor
	}
	querydsl.extendsFrom compileClasspath
}

JPAQueryFactory bean 등록

@Configuration
public class QuerydslConfiguration {
  @PersistenceContext
  private EntityManager entityManager;

  @Bean
  public JPAQueryFactory jpaQueryFactory() {
    return new JPAQueryFactory(entityManager);
  }
}

QueryDSL을 사용하기 위해 JPAQueryFactory에 bean으로 등록하고 구현체에서 이를 사용하여 쿼리를 생성한다.


Q 객체 생성

gradle에서 compile.java를 실행하면 다음과 같이 build 폴더내에 Q 객체들이 생성된다.

해당 경로는 build.gradle에서 설정한 qeurydslDir로 세팅할 수 있다.


예시

Spring Data JPA와 같이 사용하기 위해선 다음과 같은 구조가 확장성에도 좋고 OCP, DIP 원칙에 부합한다.

  • BoardRepositoryCustom
public interface BoardRepositoryCustom {
  Page<Board> findAllByMemberId(long memberId, Pageable pageable);
}
  • BoardRepositoryImpl
@Repository
@RequiredArgsConstructor
public class BoardRepositoryImpl implements BoardRepositoryCustom {
  private final JPAQueryFactory jpaQueryFactory;

  @Override
  public Page<Board> findAllByMemberId(long memberId, Pageable pageable) {
    List<Board> content = jpaQueryFactory
      .select(board)
      .from(board)
      .leftJoin(board.member, member)
      .on(member.memberId.eq(memberId))
      .offset(pageable.getOffset())
      .limit(pageable.getPageSize())
      .fetch();
    return new PageImpl<>(content, pageable, content.size());
  }
}

내가 작성한 게시글을 조회하는 기능(페이지네이션)을 구현하기 위한 쿼리이다.

  • BoardRepository
@Repository
public interface BoardRepository extends JpaRepository<Board, Long>, BoardRepositoryCustom {
}

0개의 댓글