Querydsl - 검색조건, 결과 조회, 정렬, 페이징, 집합

HotFried·2024년 2월 24일
0

Querydsl

목록 보기
3/9

검색조건

And + Or

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Test
    void search() {
        Member findMember = queryFactory
                .selectFrom(member)
                .where(member.username.eq("member1")
                        .and(member.age.eq(10))
                ).fetchOne();

        assertThat(findMember.getUsername()).isEqualTo("member1");
    }
}

and, or은 메서드 체인으로 합칠 수 있다.

And의 다른 표현법

Member findMember = queryFactory
                .selectFrom(member)
                .where(member.username.eq("member1")
                        ,(member.age.eq(10))
                ).fetchOne();

and를 이용하지말고 ,로 대체 가능


다른 검색 조건 - sql과 유사

(마크다운 표 만들기 어렵군요...)

코드분석
member.username.eq("member1")username = 'member1'
member.username.ne("member1")username != 'member1'
member.username.eq("member1").not()username != 'member1'
member.username.isNotNull()이름이 is not null
member.age.in(10, 20)age in (10,20)
member.age.notIn(10, 20)age not in (10, 20)
member.age.between(10, 30)between 10, 30
member.age.goe(30)age >= 30
member.age.gt(30)age > 30
member.age.loe(30)age <= 30
member.age.lt(30)age < 30
member.username.like("member%")like 검색
member.username.contains("member")like ‘%member%’ 검색
member.username.startsWith("member")like ‘member%’ 검색

결과 조회

fetch() : 리스트 조회, 데이터 없으면 빈 리스트 반환
fetchOne() : 단 건 조회

  • 결과가 없으면 : null
  • 결과가 둘 이상이면 : com.querydsl.core.NonUniqueResultException

fetchFirst() : limit(1).fetchOne()
fetchResults() : 페이징 정보 포함, total count 쿼리 추가 실행
fetchCount() : count 쿼리로 변경해서 count 수 조회

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Test
    void result() {
        // List
        List<Member> fetch = queryFactory
                .selectFrom(member)
                .fetch();

        // 단건
        Member findMember1 = queryFactory
                .selectFrom(member)
                .fetchOne();

        // 맨 처음 한 건만 조회
        Member findMember2 = queryFactory
                .selectFrom(member)
                .fetchFirst();

        // 페이징에서 사용
        QueryResults<Member> results = queryFactory
                .selectFrom(member)
                .fetchResults();

        // count 쿼리로 변경
        long count = queryFactory
                .selectFrom(member)
                .fetchCount();
    }
}

정렬

orderBy메소드를 이용해 정렬을 한다.

  • 파라미터로 정렬할 인자, 정렬방법을 입력해준다.
  • 메소드 체인으로 정렬할 파라미터를 여러개 넣을 수 있다.
@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    /**
     *회원 정렬 순서
     * 1. 회원 나이 내림차순(desc)
     * 2. 회원 이름 올림차순(asc)
     * 단 2에서 회원 이름이 없으면 마지막에 출력(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())
                .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();
    }
}

asc() : 오름차순
desc() : 내림차순
nullsFirst() : null을 정렬 결과의 처음으로
nullsLast() : null을 정렬 결과의 마지막으로


페이징

  • limit, offset 파라미터를 통해 페이징을 할 수 있다.

fetch

fetch()는 결과의 리스트를 조회한다.
이 때는 결과만 조회하기에 select 쿼리만 나간다.

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Test
    public void paging1() {
        List<Member> result = queryFactory
                .selectFrom(member)
                .orderBy(member.username.desc())
                // 0부터 시작(zero index)
                .offset(1)
                // 최대 2건 조회
                .limit(2)
                .fetch();

        assertThat(result.size()).isEqualTo(2);
    }
}
select
        m1_0.member_id,
        m1_0.age,
        m1_0.team_id,
        m1_0.username 
    from
        member m1_0 
    order by
        m1_0.username desc 
    offset
        ? rows 
    fetch
        first ? rows only

fetchResults

fetchResults는 페이징에 관련된 정보들을 함께 가져온다.

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Test
    public void paging2() {
        QueryResults<Member> queryResults = queryFactory
                .selectFrom(member)
                .orderBy(member.username.desc())
                .offset(1)
                .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 쿼리
는 조인이 필요 없는 경우도 있다.


자동화된 count 쿼리는 원본 쿼리와 같이 모두 조인을 해버리기 때문에 성능이 안나올 수 있다.

count 쿼리에 조인이 필요없는 성능 최적화가 필요하다면, count 전용 쿼리를 별도로 작성해야 한다.

집합

집계함수

count(), sum(), avg(), max(), min() 사용가능
이 때, 반환 타입은 Tuple을 이용한다.

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Test
    public void aggregation() throws Exception {
        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);
    }
}

GroupBy

Member엔티티를 team.name으로 group해서 이 때 team.namemember.age.avg()를 선택하고 싶다.

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @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);
    }
}

Having

GroupBy가 있으면 당연히 Having절도 사용 가능해야겠죠
아래와 같이 group한 속성에 대한 조건을 달아주면 됩니다.

@SpringBootTest
@Transactional
public class QuerydslBasicTest {

    @Test
    public void groupHaving() throws Exception {
        List<Tuple> result = queryFactory
                .select(team.name, member.age.avg())
                .from(member)
                .join(member.team, team)
                .groupBy(team.name)
                .having(team.name.eq("teamA"))
                .fetch();

        Tuple teamA = result.get(0);

        assertThat(teamA.get(team.name)).isEqualTo("teamA");
        assertThat(teamA.get(member.age.avg())).isEqualTo(15);
    }
}

참고 :

실전! Querydsl

profile
꾸준하게

0개의 댓글