QueryDSL
QueryDSL은 자바를 위한 동적 쿼리 작성을 위한 오픈 소스 라이브러리이다.
때문에 SpringBoot에 기본 내장하고 있지 않기 때문에 따로 프로젝트에 추가를 해줘야한다.
pom.xml
<!--querydsl-->
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-sql</artifactId>
</dependency>
<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.generatedAnnotationClass>com.querydsl.core.annotations.Generated</querydsl.generatedAnnotationClass>
</options>
</configuration>
</execution>
</executions>
</plugin>
위 의존성을 pom.xml에 추가한 뒤
pom.xml -> Maven -> Generate Sources and Update Folders를 누르면
프로젝트의 target -> generated-sources -> java 폴더 안에
기존의 Entity 이름 앞에 Q를 붙인 QEntity가 생성된다.
QEntity는 QueryDSL에서 엔티티를 나타내는 클래스로,
QueryDSL을 사용하여 쿼리를 작성할 때 사용한다.
-- 여기서 내가 자주했던 실수
QEntity를 생성한 뒤 기존 Entity에 값을 추가할 경우,
다시 한번 Generate Sources and Update Folders를 실행해야한다.
자동으로 QEntity를 만들어주는게 아님을 항상 생각하자.
QueryDSL은 정적 타입 검사 및 코드 자동 완성을 제공하여
쿼리 작성 시 발생할 수 있는 오류를 사전에 방지하고, 쿼리 작성을 더 편리하게 만들어 준다.
예를 들어, @Query 어노테이션을 사용할 때
@Query("SELECT p.category, SUM(o.quantity) " +
"FROM Product p " +
"JOIN p.orders o " +
"WHERE p.category = :category " +
"GROUP BY p.catgory")
List<Orders> findBySalesSum(@Param("category") String category);
위 쿼리는 얼핏보면 오류가 없어보이지만
잘보면 Group By 절에 p.catgory , 오타가 있는 쿼리이다.
이처럼 @Query절은 유용하게 사용할 수 있지만
쿼리를 작성중에 개발자가 할 수 있는 실수를 캐치할 수 없는 단점 아닌 단점이 존재한다.
굉장히 유능한 시니어라면 실수도 안하겠지만 !
QueryDSL을 사용하여 쿼리를 작성하면 위 같은 오타를 IDE에서 발견해주기 때문에
나같은 주니어 개발자들이 오타를 걱정하지 않고 쿼리를 작성할 수 있게 도와준다.
생성자를 기준으로 DTO를 Entity와 매핑시키는게 가장 보편적인 방법이다.
반드시 생성자 기준으로 모든 파라미터가 구현되어야 하며,
하나라도 더 많거나 없다면 생성 자체가 되지 않는다.
DTO.class 를 따로 작성하여 @QueryProjections 어노테이션을 통해 생성자를 주입한다
@QueryProjections을 DTO.class 붙인 뒤 compile하면 DTO.class도 QClass가 생긴다!
// DTO.class
public class UserDTO {
private String name;
private int age;
@QueryProjection // QueryProjection으로 생성자 주입
public UserDTO(String name, int age) {
this.name = name;
this.age = age;
}
}
Service 단의 class에서 위 생성자를 기준으로 DTO와 매핑한다.
// service.class
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QUserEntity qUserEntity = QUserEntity.userEntity;
List<UserDTO> users = queryFactory
.select(new QUserDto(qUserEntity.name, qUserEntity.age)
.from(qUserEntity)
.fetch();
이런식으로 @QueryProjections 어노테이션을 통해
Entity와 DTO를 매핑시키는 관계에서 QueryDSL을 사용할 수 있다.
오타를 방지하고, DTO의 형태도 사전에 정한대로 만들기 때문에 개발자의 실수를 방지할수있다.