Querydsl
Querydsl은 JPA, Hibernate 등 다양한 ORM 프레임워크와 호환되며, 개체지향 쿼리 언어를 사용하여 타입 세이프한 쿼리를 작성할 수 있는 라이브러리이다.
프로젝션(Projection)
프로젝션은 select절에서 사용되며 쿼리 결과를 원하는 개체나 값으로 변환해주는 기능을 제공한다.
Queyrdsl에서 프로젝션을 사용하는 방법
프로젝션을 사용해서 DTO를 조회하는 방법은 크게 4가지 방법이 있다.
- @QueryProjection
- Projections.bean()
- Projections.constructor()
- Projections.fields()
@QueryProjection
@QueryProjection은 생성자에 생성자 방식으로 프로젝션을 수행한다. 이 방식은 컴파일 시에 생성자를 만들어주기 때문에 런타임 오류를 방지할 수 있고, 코드의 가독성을 높여준다.
방법은 간단하다. DTO의 생성자에 @QueryProjection을 붙여주면 된다. 이후 빌드를 하면 해당 DTO의 Q파일이 생성된다.
public class TagDto {
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public static class Response {
String name;
Long count;
@Builder
@QueryProjection
public Response(String name, Long count) {
this.name = name;
}
}
}
생성된 Q타입으로 일반 객체를 생성하듯이 Querydsl에서 사용할 수 있다.
@Repository
@RequiredArgsConstructor
public class TagCustomRepositoryImpl implements TagCustomRepository {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<TagDto.Response> findTagsStartingWith(String tagName, int size) {
return jpaQueryFactory.select(
new QTagDto_Response(tag.name))
.from(tag)
.where(tag.name.startsWith(tagName))
.limit(size)
.orderBy()
.fetch();
}
}
@QueryProjection을 사용하면 컴파일 시에 타입 체크를 할 수 있어서 가장 안전하고 추천되는 방법이다. 하지만 DTO Q클래스를 생성하고 유지보수해야 하는 불편함이 있다.
Projections.bean()
프로퍼티로 접근하는 방법이다. Setter를 사용하기 때문에 Setter와 기본 생성자가 있어야 한다. Reflection을 사용하기 때문에 속도가 느릴 수 있다.
@Repository
@RequiredArgsConstructor
public class TagCustomRepositoryImpl implements TagCustomRepository {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<TagDto.Response> findTagsStartingWith(String tagName, int size) {
return jpaQueryFactory.select(
Projections.bean(TagDto.Response.class, tag.name))
.from(tag)
.where(tag.name.startsWith(tagName))
.limit(size)
.orderBy()
.fetch();
}
}
Projections.fields()
필드를 통해 접근하는 방법이다. 필드와 기본 생성자가 필수적으로 있어야 한다. DTO 클래스와 엔티티 클래스의 필드명이 같아야 하기 때문에 유연성이 떨어진다. 하지만 가장 빠른 속도를 보장한다.
@Repository
@RequiredArgsConstructor
public class TagCustomRepositoryImpl implements TagCustomRepository {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<TagDto.Response> findTagsStartingWith(String tagName, int size) {
return jpaQueryFactory.select(
Projections.fields(TagDto.Response.class, tag.name))
.from(tag)
.where(tag.name.startsWith(tagName))
.limit(size)
.orderBy()
.fetch();
}
}
Projections.constructor()
생성자를 통해 접근하는 방법이다. 명시적으로 DTO 클래스의 생성자를 지정할 수 있기 때문에 유연성이 높다. 하지만 DTO 클래스의 생성자가 변경될 때마다 쿼리도 변경해줘야하는 번거로움이 있다.
@Repository
@RequiredArgsConstructor
public class TagCustomRepositoryImpl implements TagCustomRepository {
private final JPAQueryFactory jpaQueryFactory;
@Override
public List<TagDto.Response> findTagsStartingWith(String tagName, int size) {
return jpaQueryFactory.select(
Projections.constructor(TagDto.Response.class, tag.name))
.from(tag)
.where(tag.name.startsWith(tagName))
.limit(size)
.orderBy()
.fetch();
}
}
'SQL' 카테고리의 다른 글
SQL - MySQL 워크밴치에서 Foreign key 삭제하기 (0) | 2023.06.20 |
---|---|
MySQL - 프로그래머스 164670. 조건에 맞는 사용자 정보 조회하기 (0) | 2023.05.29 |
MySQL - 프로그래머스 157341. 대여 기록이 존재하는 자동차 리스트 구하기 (MONTH( ) 함수) (0) | 2023.05.06 |
MySQL - 프로그래머스 131529. 카테고리 별 상품 개수 구하기 (문자열 자르기) (0) | 2023.05.02 |
SQL - 프로그래머스 131124. 재구매가 일어난 상품과 회원 리스트 구하기. 재구매가 일어난 상품과 회원 리스트 구하기 (0) | 2023.04.28 |