[Querydsl] 검색 쿼리를 Querydsl로 구현하기(3)
프로젝션
프로젝션이란 select 대상을 지정하는 것을 말한다.
프로젝션 대상이 하나일 경우
List<String> result = queryFactory
.select(member.username)
.from(member)
.fetch();
프로젝션 대상이 둘 이상일 경우
튜플 혹은 DTO를 사용해 조회한다.
튜플 조회
List<Tuple> result = queryFactory
.select(member.username, member.age)
.from(member)
.fetch();
DTO 조회
Querydsl에서 DTO를 직접 반환할 수 있는 방법은 4가지가 있다.
1) 프로퍼티 접근
List<MemberDto> result = queryFactory
.select(Projections.bean(MemberDto.class, member.username, member.age))
.from(member)
.fetch();
2) 필드 직접 접근
List<MemberDto> result = queryFactory
.select(Projections.fields(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
3) 생성자 사용
List<MemberDto> result = queryFactory
.select(Projections.constructor(MemberDto.class,
member.username,
member.age))
.from(member)
.fetch();
4) @QueryProjection 사용
DTO 클래스의 생성자에 아래와 같이 @QueryProjection을 적어둔다.
@Data
public class MemberDto {
private String username;
private int age;
@QueryProjection
public MemberDto(String username, int age) {
this.username = username;
this.age = age;
}
}
주의할 점은 아래 명령어를 사용해서 QMemberDto를 생성해야 한다.
./gradlew compileQuerydsl
이 방법이 컴파일러 전에 타입 체크를 할 수 있어 가장 안전한 방법이다. 그러나 DTO에 Querydsl 어노테이션을 사용하는 점과 Q 클래스를 생성해야 하는 단점이 있다.
개인적인 생각으로는 극한의 성능을 추구하는 것이 아니라면 엔티티를 조회한 후 DTO로 직접 반환하는 것이 좋아 보인다.
동적 쿼리
Querydsl에서 동적 쿼리를 다음과 같이 두 가지 방식을 지원해준다.
BooleanBuilder 방식
String usernameParam = "member1";
Integer ageParam = null;
BooleanBuilder builder = new BooleanBuilder();
if (usernameParam != null) {
builder.and(member.username.eq(usernameParam));
}
if (ageParam != null) {
builder.and(member.age.eq(ageParam));
}
List<Member> result = queryFactory
.selectFrom(member)
.where(builder)
.fetch();
파라미터의 NULL값을 체크한 뒤 BooleanBuild를 사용해 where 절을 생성해준다.
하지만 이 방법은 직접 NULL값을 체크해야 하는 단점이 있다. 파라미터가 많으면 코드가 매우 길어진다. 이 방법을 해결하기 위해 Querydsl은 Where 다중 파라미터 방식을 지원해준다.
Where 다중 파라미터 방식
private List<Member> searchMember2(String usernameParam, Integer ageParam) {
return queryFactory
.selectFrom(member)
.where(usernameEq(usernameParam), ageEq(ageParam))
.fetch();
}
private BooleanExpression usernameEq(String usernameParam) {
return usernameParam != null ? member.username.eq(usernameParam) : null;
}
private BooleanExpression ageEq(Integer ageParam) {
return ageParam != null ? member.age.eq(ageParam) : null;
}
Where 절의 조건에 NULL값은 무시된다. 따라서 파라미터마다 삼항 연산자로 NULL값을 체크하는 메서드를 생성해 Where 절에서 호출할 수 있다. 쿼리의 코드가 간결해지고 가독성이 높아진다.
메서드를 다른 쿼리에서 사용할 수 있고, 아래와 같이 조합해서 활용할 수 있다.
private List<Member> searchMember2(String usernameParam, Integer ageParam) {
return queryFactory
.selectFrom(member)
.where(allEq(usernameParam, ageParam))
.fetch();
}
private BooleanExpression usernameEq(String usernameParam) {
return usernameParam != null ? member.username.eq(usernameParam) : null;
}
private BooleanExpression ageEq(Integer ageParam) {
return ageParam != null ? member.age.eq(ageParam) : null;
}
// 메소드 조합
private BooleanExpression allEq(String usernameParam, Integer ageParam) {
return usernameEq(usernameParam).and(ageEq(ageParam));
}
참고
김영한 님의 실전! Querydsl
김영한님의 자바 ORM 표준 JPA 프로그래밍
'개발 > JPA' 카테고리의 다른 글
[JPA] 영속성 관리 (0) | 2021.12.08 |
---|---|
[JPA] JPA 소개 (0) | 2021.12.08 |
[Querydsl] 검색 쿼리를 Querydsl로 구현하기(2) (0) | 2021.07.14 |
[Querydsl] 검색 쿼리를 Querydsl로 구현하기(1) (0) | 2021.07.14 |
[Querydsl] 스프링 부트에 Querydsl 설정하기 (0) | 2021.07.14 |
댓글