QueryDSL 이란?
정적 타입을 이용해 SQL과 같은 쿼리를 생성할 수 있게 지원하는 프레임워크
문자열이나 XML파일을 통해 쿼리를 작성하는 대신 QueryDSL이 제공하는 Fluent API를 활용해 쿼리 작성 가능
장점
- IDE에서 제공하는 코드 자동완성 기능 사용 가능
- 문법적으로 잘못된 쿼리 허용 X
- 고정된 SQL쿼리를 작성하지 않기에 동적으로 쿼리 생성 가능
- 코드를 작성하므로 가독성 + 생산성 향상
- 도메인타입과 프로퍼티를 안전하게 참조 가능
QueryDSL을 사용하기 위한 프로젝트 설정
의존성 추가
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
< plugins > 태그에 APT 플러그인 추가
<plugin>
<groupId>com.mysema.maven</groupId>
<artifactId>apt-maven-plugin</artifactId>
<version>1.1.3</version>
<executions>
<execution>
<goals>
<goal>process</goal>
</goals>
<configuration>
<outputDirectory>target/generated-sources/java</outputDirectory>
<processor>com.querydsl.apt.jpa.JPAAnnotationProcessor</processor>
<options>
<querydsl.entityAccessors>true</querydsl.entityAccessors>
</options>
</configuration>
</execution>
</executions>
</plugin>
JPAAnnotationProcessor은 @Entity 어노테이션으로 정의된 엔티티 클래스를 찾아서 쿼리 타입 생성
이후 maven lifecycle -> compile 단계 클릭해 빌드 수행

그러면 Q 도메인 클래스가 생성된 것을 볼 수 있다
QueryDSL은 지금까지 작성했었던 엔티티 클래스와 QDomain이라는 쿼리 타입의 클래스를 자체적으로 생성해서 메타데이터로 사용
-> 이를 통해 SQL과 같은 쿼리를 생성하여 제공

generated-sources를 Mark as Sources로 하여 IDE에서 소스 파일로 인식할 수 있게 해주어야 함
기본적인 QueryDSL 사용
@PersistenceContext
EntityManager entityManager;
@Test
void queryDslTest(){
JPAQuery<Product> query = new JPAQuery(entityManager);
QProduct qProduct = QProduct.product;
List<Product> productList = query
.from(qProduct)
.where(qProduct.name.eq("펜"))
.orderBy(qProduct.price.asc())
.fetch();
for(Product product : productList){
System.out.println("-----------------");
System.out.println();
System.out.println("Product Number : " + product.getNumber());
System.out.println("Product Name : " + product.getName());
System.out.println("Product Price :" + product.getPrice());
System.out.println("Product Stock :" + product.getStock());
System.out.println();
System.out.println("-------------------");
}
}
위 코드는 QueryDSL에 의해 생성된 Q도메인 클래스를 활용하는 코드
Q도메인 클래스와 대응되는 테스트 클래스가 없으므로 엔티티 클래스에 대응되는 리포지토리의 테스트 클래스에 포함해도 무관
QueryDSL을 사용하기 위해선 JPAQuery 객체를 사용
-> EntityManager를 활용하여 생성
생성된 JPAQuery는 9~13번 줄 같이 빌더 형식으로 쿼리 작성
List로 반환 받기 위해서는 fetch() 메서드를 사용해야 함
반환 메서드 종류
- List< T > fetch() : 조회 결과를 리스트로 반환
- T fetchOne : 단 한건의 조회 결과 반환
- T fetchFirst() : 여러 건의 조회 결과중 1건을 반환
- Long fetchCount() : 조회 결과의 개수를 반환
- QueryResult< T > fetchResults() : 조회 결과 리스트와 개수를 포함한 QueryResults 반환
QueryDSL을 사용하기 위해 JPAQueryFactory를 사용하는 경우도 있음
JPAQueryFactory를 활용한 QueryDSL 테스트 코드
@Test
void queryDslTest2(){
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QProduct qProduct = QProduct.product;
List<Product> productList = jpaQueryFactory.selectFrom(qProduct)
.where(qProduct.name.eq("펜"))
.orderBy(qProduct.price.asc())
.fetch();
for(Product product : productList){
System.out.println("-----------------");
System.out.println();
System.out.println("Product Number : " + product.getNumber());
System.out.println("Product Name : " + product.getName());
System.out.println("Product Price :" + product.getPrice());
System.out.println("Product Stock :" + product.getStock());
System.out.println();
System.out.println("-------------------");
}
}
JPAQuery를 사용했을 때와 달리 JPAQueryFactory에서는 select 절부터 가능
일부만 조회하고 싶다면 selectFrom()이 아닌 select()와 From() 메서드 구분해서 사용하자
@Test
void queryDslTest3(){
JPAQueryFactory jpaQueryFactory = new JPAQueryFactory(entityManager);
QProduct qProduct = QProduct.product;
List<String> productList = jpaQueryFactory
.select(qProduct.name)
.from(qProduct)
.where(qProduct.name.eq("펜"))
.orderBy(qProduct.price.asc())
.fetch();
for(String product : productList){
System.out.println("-------------------");
System.out.println("Product Name : " + product);
System.out.println("------------------");
}
List<Tuple> tupleList = jpaQueryFactory
.select(qProduct.name, qProduct.price)
.from(qProduct)
.where(qProduct.name.eq("펜"))
.orderBy(qProduct.price.asc())
.fetch();
for(Tuple product : tupleList){
System.out.println("----------");
System.out.println("Product Name :" + product.get(qProduct.name));
System.out.println("Product Name :" + product.get(qProduct.price));
System.out.println("----------");
}
}
productList는 select 대상이 하나인 경우
TupleList처럼 select 대상이 여러개인 경우 쉼표로 구분해서 작성하면 되고, 리턴 타입을 List< tuple > 로 작성
'Study > 개발일지' 카테고리의 다른 글
[백엔드온라인TIL] java 학습 33일차 (1) | 2023.07.10 |
---|---|
[백엔드스터디WIL]7주차 학습일지 (0) | 2023.07.07 |
[KPT회고] 9조 프로젝트 이후 회고록 (0) | 2023.07.07 |
[spring] 뉴스피드 프로젝트 진행상황 (0) | 2023.07.07 |
[백엔드온라인TIL] java 학습 31일차 (0) | 2023.07.06 |