JPA/Querydsl
Querydsl - 정렬과 페이징, 집합
chanhee01
2023. 8. 12. 23:28
정렬
/**
* 회원 정렬 순서
* 1. 회원 나이 내림차순(desc)
* 2. 회원 이름 올림차순(asc)
* 만약, 회원 이름이 없으면 마지막에 출력(nulls last)
*/
@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())
// nullsLast는 해당 데이터가 null이면 마지막으로 정렬 (nullsFirst는 맨 앞으로)
.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();
}
기본 데이터들의 나이는 적기 때문에 테스트를 위해 새로 persist한 데이터들이 조건에 의해서 먼저 나오게 될 것이다. 나이가 많은 순으로 정렬하고 이름 순으로 올림차순 했으니 member5가 첫 번째, member6가 두 번째이다. memberNull은 이름이 없다. 하지만 member.username.asc().nullsLast라는 문장에 의해 나이로 정렬로 한 뒤, 이름의 정렬을 할 때 맨 뒤로 가기때문에 나이가 같은 member5, member6 바로 아래에서 조회가 되는 것이다.
desc(), asc()로 기본 정렬
nullsLast(), nullsFirst()로 null 값 정렬
페이징
@Test
public void paging1() {
List<Member> result = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(0)
.limit(2)
.fetch();
assertThat(result.size()).isEqualTo(2);
}
@Test
public void paging2() { // 전체 조회수까지 필요할 때
QueryResults<Member> result = queryFactory
.selectFrom(member)
.orderBy(member.username.desc())
.offset(0)
.limit(2)
.fetchResults();
assertThat(result.getTotal()).isEqualTo(4);
assertThat(result.getLimit()).isEqualTo(2);
assertThat(result.getOffset()).isEqualTo(0);
assertThat(result.getResults().size()).isEqualTo(2);
}
전체 조회 개수가 필요하면 paging2()처럼 fetchResults()로 결과를 조회하면 된다.
하지만 성능 상 전체 조회 개수를 분리해야 한다면 paging1()처럼 fetch()를 사용하면 된다.
집합
@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);
}
count(), sum() 등의 집합을 사용하는데 JPQL과 방법이 매우 유사해서 별도의 설명 없이 이해할 수 있을 것이다.
@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)
.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);
}
groupBy를 team.name으로 해오는 것이다. 반환 타입이 Tuple의 리스트로 반환되는 특징이 있다.
Querydsl을 공부하고 있는데 기본적으로 JPQL과 많이 겹치는데 JPQL을 간편하게 해주는 것이라 이해하기 어렵진 않지만 JPQL을 더 확실하게 공부하고 Querydsl도 실수 없이 사용할 수 있도록 익숙해져야 한다는 생각이 들었다.