내가 공부한 것을 올리며, 중요한 단원은 저 자신도 곱씹어 볼 겸 상세히 기록하고 얕은 부분들은 가볍게 포스팅하겠습니다.
5. 정렬
QueryDSL을 통해 정렬을 해보자!
- desc() , asc() : 일반 정렬
- nullsLast() , nullsFirst() : null 데이터 순서 부여
@Test
public void sort() {
// given
em.persist(new Member(null, 100));
em.persist(new Member("member5", 100));
em.persist(new Member("member6", 100));
// when
List<Member> members = queryFactory
.selectFrom(member)
.where(member.age.eq(100))
.orderBy(member.age.desc(), member.username.asc().nullsLast())
.fetch();
Member member5 = members.get(0);
Member member6 = members.get(1);
Member memberNull = members.get(2);
// then
assertThat(member5.getUsername()).isEqualTo("member5");
assertThat(member6.getUsername()).isEqualTo("member6");
assertThat(memberNull.getUsername()).isNull();
}
위 테스트 코드를 통해 알아보자.
orderBy에 보면 desc()로 내림차순으로 정렬하고, nullsLast()와 같이 Null을 맨 뒤로 보내는 편리한 기능도 지원해준다.
나이는 모두 동일하게 100살이니 무시하고, 이름이 오름차순으로 되니 member5, member6, null 순으로 정렬된다.
실행되는 쿼리는 다음과 같다.
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
6. 페이징
6-1) 일부분만 페이징 하는 경우
다음과 같이 테스트코드를 작성하였다.
@Test
public void paging_test() {
// given
List<Member> members = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(1)
.limit(2)
.fetch();
// then
assertThat(members.size()).isEqualTo(2);
}
성공적으로 테스트가 통과되며, 생성되는 SQL은 다음과 같다.
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 2 offset 1
6-2) 전체 조회 수가 필요한 경우
@Test
public void all_paging_test() {
// given
QueryResults<Member> queryResults = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(1)
.limit(2)
.fetchResults();
// then
assertThat(queryResults.getTotal()).isEqualTo(4);
assertThat(queryResults.getLimit()).isEqualTo(2);
assertThat(queryResults.getOffset()).isEqualTo(1);
assertThat(queryResults.getResults().size()).isEqualTo(2);
}
다만 위 코드와 같이 fetchResults를 사용하는 방식은 count 쿼리가 원본 쿼리와 같이 모두 조인을 해버리기 때문에 성능이 안나올 수 있다.
count 쿼리에 조인이 필요없는 성능 최적화가 필요하다면, count 전용 쿼리를 별도로 작성하는것을 추천한다.
7. 집합
7-1) 집합 함수 코드
@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인것을 확인할 수 있다.
반환값이 한가지 타입이 아닌, 여러개의 type을 반환하는 경우 tuple을 사용한다.
하지만 실무에서는 Tuple을 사용하기 보다는 DTO로 직접 조회하는 방식을 더 자주 사용한다.
7-2) Group By 사용
@Test
@DisplayName("팀의 이름과 각 팀의 평균 연령 구하기")
public void group_test() {
List<Tuple> result = queryFactory
.select(team.name, member.age.avg())
.from(member)
.join(member.team, team)
.groupBy(team.name)
.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(20);
}
groupBy에 조건을 걸려면 having() 또한 사용 가능하다.
예를들어 member의 age로 group by를 하되, 20살 이상만 그룹화 하려면?
.groupBy(member.age)
.having(member.age.gt(20))
'BackEnd > JPA' 카테고리의 다른 글
[JPA] QueryDSL 기본문법 - 4 (0) | 2022.05.14 |
---|---|
[JPA] QueryDSL 기본문법 - 3 (0) | 2022.05.14 |
[JPA] QueryDSL 기본문법 - 1 (0) | 2022.05.13 |
[JPA] 나머지 기능들 (0) | 2022.05.07 |
[JPA] 스프링 데이터 JPA 분석 (0) | 2022.05.06 |
댓글