반응형
Query DSL게시글은 대부분 인프런의 김영한님의 강의인 '실전! Query DSL' 기반으로 내용을 정리했습니다.
정렬
정렬 기준은 다음과 같다.
- 회원 나이 내림차순(desc)
- 회원 이름 오름차순(asc)
- 단, 회원 이름이 없으면 마지막에 출력한다.
@Test
public void sort() {
em.persist(new Member(null, 100));
em.persist(new Member("member5", 100));
em.persist(new Member("member6", 100));
List<Member> result = queryFactory
.selectFrom(member)
.where(member.age.eq(100))
.orderBy(member.age.desc(), member.username.asc().nullsLast())
.fetch();
Member member5 = result.get(0);
Member member6 = result.get(1);
Member memberNull = result.get(2);
assertThat(member5.getUsername()).isEqualTo("member5");
assertThat(member6.getUsername()).isEqualTo("member6");
assertThat(memberNull.getUsername()).isNull();
}
/* select
member1
from
Member member1
where
member1.age = ?1
order by
member1.age desc,
member1.username asc nulls last */ select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
where
member0_.age=?
order by
member0_.age desc,
member0_.username asc nulls last
참고로 nullsLast() 말고 nullsFirst()도 존재한다. nullsFirst()를 사용할 경우 회원 이름에 null 값이 존재하는 회원이 제일 위로 정렬된다. nullsFirst로 변경하면 검증은 아래와 같다.
Member memberNull = result.get(0);
Member member5 = result.get(1);
Member member6 = result.get(2);
assertThat(memberNull.getUsername()).isNull();
assertThat(member5.getUsername()).isEqualTo("member5");
assertThat(member6.getUsername()).isEqualTo("member6");
페이징
@Test
public void paging1() {
List<Member> result = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(1) // 0부터 시작
.limit(2)
.fetch();
assertThat(result.size()).isEqualTo(2);
}
/* select
member1
from
Member member1
order by
member1.username desc */ select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
order by
member0_.username desc limit ? offset ?
전체 조회 수가 필요할 경우
@Test
public void paging2() {
QueryResults<Member> queryResults = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(1) // 0부터 시작
.limit(2)
.fetchResults();
assertThat(queryResults.getTotal()).isEqualTo(4);
assertThat(queryResults.getLimit()).isEqualTo(2);
assertThat(queryResults.getOffset()).isEqualTo(1);
assertThat(queryResults.getResults().size()).isEqualTo(2);
}
// count query
/* select
count(member1)
from
Member member1 */ select
count(member0_.member_id) as col_0_0_
from
member member0_
// paging query
/* select
member1
from
Member member1
order by
member1.username desc */ select
member0_.member_id as member_i1_1_,
member0_.age as age2_1_,
member0_.team_id as team_id4_1_,
member0_.username as username3_1_
from
member member0_
order by
member0_.username desc limit ? offset ?
참고로 count 쿼리가 따로 실행되는 만큼 성능을 주의해야 한다. 페이징 쿼리를 작성할 때 복잡한 조인이 일어나는 경우, count 쿼리는 조인이 필요 없을 수도 있다. 이런 상황에서 fetchResults()로 count 쿼리까지 가져오면 count 쿼리마저 조인이 일어나 성능이 저하되므로 이런 경우에는 분리해서 따로 작성하는 게 맞다.
집합
@Test
public void aggregation() {
List<Tuple> result = queryFactory
.select(member.count(),
member.age.sum(),
member.age.avg(),
member.age.max(),
member.age.min())
.from(member)
.fetch();
Tuple tuple = result.get(0);
assertThat(tuple.get(member.count())).isEqualTo(4);
assertThat(tuple.get(member.age.sum())).isEqualTo(100);
assertThat(tuple.get(member.age.avg())).isEqualTo(25);
assertThat(tuple.get(member.age.max())).isEqualTo(40);
assertThat(tuple.get(member.age.min())).isEqualTo(10);
}
Tuple은 QueryDSL에서 제공하는 타입이다. 여러 타입을 반환 받을 때 주로 사용하며 더 자세한 내용은 추후에 설명한다.
집합 함수는 JPQL이 제공하는 모든 집합 함수를 사용할 수 있다.
GroupBy
각 팀별 회원 나이의 평균을 구해보자.
@Test
public void group() throws Exception {
List<Tuple> result = queryFactory
.select(team.name, member.age.avg())
.from(member)
.join(member.team, team) // 나중에 설명!
.groupBy(team.name) // team의 이름으로 grouping
.fetch();
Tuple teamA = result.get(0);
Tuple teamB = result.get(1);
assertThat(teamA.get(team.name)).isEqualTo("teamA");
assertThat(teamA.get(member.age.avg())).isEqualTo(15);
assertThat(teamB.get(team.name)).isEqualTo("teamB");
assertThat(teamB.get(member.age.avg())).isEqualTo(35);
}
.having()도 groupBy 체인에 이어서 사용할 수 있다.
반응형