본문 바로가기
JPA/Querydsl

Querydsl 03 - 기본문법(정렬, 페이징, 집합)

by 킹차니 2022. 1. 17.

정렬

orderBy 안에 조건을 추가하여 정렬이 가능하다. 바로 코드로 보자.

/*
   *회원 정렬 순서
   1. 회원 나이 내림차순(desc)
   2. 회원 이름 내림차순 (desc)
   3. 단, 2에서 회원 이름이 없으면 마지막에 출력(null last)
 */
@Test
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))//100살인 회원
            .orderBy(member.age.desc(),//나이 내림차순
                    member.username.desc(),//이름 내림차순
                    member.username.asc().nullsLast())//username null이면 맨 마지막
            .fetch();
    Member member6 = result.get(0);
    Member member5 = result.get(1);
    Member memberNull = result.get(2);
    assertThat(member5.getUsername()).isEqualTo("member5");
    assertThat(member6.getUsername()).isEqualTo("member6");
    assertThat(memberNull.getUsername()).isNull();
    for (Member m : result) System.out.println("m = " + m);
}

// --> 테스트 성공
출력결과:
m = Member(id=9, username=member6, age=100)
m = Member(id=8, username=member5, age=100)
m = Member(id=7, username=null, age=100)

• desc() , asc() : 일반 정렬
 nullsLast() , nullsFirst() : null 데이터 순서 부여

 


페이징

offset와 limit을 사용하여 페이징이 가능하다.

 

@Transactional
@SpringBootTest
public class QuerydslBasicTest {

    @Autowired EntityManager em;

    JPAQueryFactory queryFactory;

    @BeforeEach
    public void before(){
        queryFactory = new JPAQueryFactory(em);

        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);

        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 10, teamA);
        Member member3 = new Member("member3", 10, teamB);
        Member member4 = new Member("member4", 10, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
    }

    @Test
    void paging1() {


        List<Member> result = queryFactory.selectFrom(member)
                .orderBy(member.username.desc())
                .offset(1)//몇개 건너뛸건지
                .limit(2)//몇개 뽑아낼건지
                .fetch();
        assertThat(result.size()).isEqualTo(2);
        for (Member m : result) System.out.println("m = " + m);
    }
}
// -> 테스트 성공
출력결과:
m = Member(id=5, username=member3, age=10)
m = Member(id=4, username=member2, age=10)
주의: count 쿼리가 실행되니 성능상 주의하자.
참고: 페이징 쿼리를 작성할 때, 데이터를 조회하는 쿼리는 여러 테이블을 조인해야 하지만, count 쿼리는 조인이 필요 없는 경우도 있다. 그런데 이렇게 자동화된 count 쿼리는 원본 쿼리와 같이 모두 조인을 해버리기 때문에 성능이 안나올 수 있다. count 쿼리에 조인이 필요없는 성능 최적화가 필요하다면, count 전용 쿼리를 별도로 작성해야 한다.

 


집합

@Test
void aggregation() {
    //querydsl에서 제공하는 Tuple
    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);

    Long memberCnt = tuple.get(member.count());
    Integer sumAge = tuple.get(member.age.sum());
    Double avgAge = tuple.get(member.age.avg());
    Integer maxAge = tuple.get(member.age.max());
    Integer minAge = tuple.get(member.age.min());

    assertThat(memberCnt).isEqualTo(4);
    assertThat(sumAge).isEqualTo(40);
    assertThat(avgAge).isEqualTo(10);
    assertThat(maxAge).isEqualTo(10);
    assertThat(minAge).isEqualTo(10);
}

 

• JPQL이 제공하는 모든 집합 함수를 제공한다.

• tuple은 프로젝션과 결과반환에서 설명한다.

 

 

 

Group by

@Transactional
@SpringBootTest
public class QuerydslBasicTest {

    @Autowired EntityManager em;

    JPAQueryFactory queryFactory;

    @BeforeEach
    public void before(){
        queryFactory = new JPAQueryFactory(em);

        Team teamA = new Team("teamA");
        Team teamB = new Team("teamB");
        em.persist(teamA);
        em.persist(teamB);

        Member member1 = new Member("member1", 10, teamA);
        Member member2 = new Member("member2", 20, teamA);
        Member member3 = new Member("member3", 10, teamB);
        Member member4 = new Member("member4", 20, teamB);
        em.persist(member1);
        em.persist(member2);
        em.persist(member3);
        em.persist(member4);
    }

 
    /*
    * 팀의 이름과 각 팀의 평균 연령을 구하라
    * */
    @Test
    void aggregation2() {
        List<Tuple> result = queryFactory.select(QTeam.team.name, member.age.avg())
                .from(member)
                .join(member.team, QTeam.team)
                .groupBy(QTeam.team.name)
                .fetch();
        Tuple teamA = result.get(0);
        Tuple teamB = result.get(1);

        System.out.println("teamA = " + teamA);
        assertThat(teamA.get(QTeam.team.name)).isEqualTo("teamA");
        assertThat(teamA.get(member.age.avg())).isEqualTo(15);

        System.out.println("teamB = " + teamB);
        assertThat(teamB.get(QTeam.team.name)).isEqualTo("teamB");
        assertThat(teamB.get(member.age.avg())).isEqualTo(15);
    }
}

// --> 테스트 성공

출력결과:
teamA = [teamA, 15.0]
teamB = [teamB, 15.0]

 - groupBy , 그룹화된 결과를 제한하려면 having

 

 

 

김영한님의 인프런 강의와 PDF를 바탕으로 정리하였습니다.