본문 바로가기

백엔드/QueryDSL

쿼리 dsl 기초

QType

쿼리dsl 컴파일러가 실행되면 엔티티들을 대상으로 QType 클래스들을 만든다. 쿼리 dsl에서는 이 QType 클래스를 대상으로 쿼리를 만들어낸다.

Q클래스 인스턴스의 사용법 2가지

  1. QMember qmem = new Qmember("m"); // 별칭을 주며 직접 생성하기
  2. QMember qmem = QMember.member; 싱글톤으로 구현된 기본 인스턴스 사용하기

 

1번 방법은 직접 별칭을 주는 것이고 2번의 방법은 기본값을 사용하는 것이다.

 

해당 QType 인스턴스를 대상으로 쿼리를 생성하면 아래와 같은 쿼리가 생긴다.

위에서 Qtype의 별칭은 sql로 번역이 될때 테이블 별칭을 말한다.

 

다양한 쿼리

Qtype 인스턴스가 제공해주는 다양한 함수들을 통해 where에 여러 조건을 주는 것이 가능하다.

Member m1 = qf.selectFrom(member)
.where(member.username.eq("m1").and(member.age.eq(10))).fetchOne();

m1 = qf.selectFrom(member)
.where(member.username.eq("m1").or(member.age.eq(13))).fetchOne();

m1 = qf.selectFrom(member)
.where(member.age.between(9, 11)).fetchOne();

or 조건
between 함수

 

and 조건의 경우에는 and 함수를 쓸 수도 있지만 

Member m1 = qf.selectFrom(member)
		.where(member.username.eq("m1"),
                 member.age.eq(10))
        .fetchOne();

이렇게 where 내부에 여러개를 넘기면 모두 and 조건으로 묶이게 된다. 이렇게 하면 동적 쿼리를 훨씬 깔끔하게 짤 수 있기 때문에 and 조건의 경우에는 이와 같은 방식으로 하는 것이 좋다.

 

결과 조회하기

  • 결과 하나만 조회 : fetchOne  (결과가 없거나 둘 이상이면 에러)
  • 리스트로 조회 : fetch
  • 첫번째 결과만 조회 : fetchFirst
  • count쿼리 : fetchCount
  • 페이징 : fetchResults

 

fetchResults 예시 코드

    @Test
    public void search() {
        QueryResults<Member> memberQueryResults = qf.selectFrom(member)
                .fetchResults();
        long total = memberQueryResults.getTotal();
        System.out.println(total);
        List<Member> results = memberQueryResults.getResults();
        for (Member result : results) {
            System.out.println(result.getAge());
        }
    }

전체 결과 갯수 조회를 위해서 count 쿼리가 먼저 하나 나간다. (참고로 /* ~~  */ 내부는 jpql)

 

정렬, 페이징, 집합

1. 정렬

// 정렬
em.persist(new Member("a", 100));
em.persist(new Member("a", 105));
em.persist(new Member("b", 105));

List<Member> result = qf.selectFrom(member).where(member.age.between(100, 105))
	.orderBy(member.age.desc(), member.username.asc().nullsLast()).fetch();
for (Member member1 : result) {
	System.out.println("member1.getAge() = " + member1.getAge() + member1.getUsername());
}

2. 페이징

//페이징
QueryResults<Member> memberQueryResults = qf.selectFrom(member)
                                    .orderBy(member.username.desc())
                                    .offset(1)
                                    .limit(2)
                                    .fetchResults();
assertThat(memberQueryResults.getTotal()).isEqualTo(3);
assertThat(memberQueryResults.getLimit()).isEqualTo(2);
assertThat(memberQueryResults.getOffset()).isEqualTo(1);
assertThat(memberQueryResults.getResults().size()).isEqualTo(2);

 

3. aggregation

// aggregation 함수들 사용해보기
//Tuple은 여러개 타입이 있을 때 꺼내올 수 있는 것.
List<Tuple> result = qf.select(
      member.count(),
      member.age.sum(),
      member.age.avg(),
      member.age.max()
).from(member).fetch();

Tuple tuple = result.get(0);
assertThat(tuple.get(member.count())).isEqualTo(3);
assertThat(tuple.get(member.age.sum())).isEqualTo(37);
assertThat(tuple.get(member.age.max())).isEqualTo(15);

 

// group by
List<Tuple> fetch = qf.select(team.name, member.age.avg())
                .from(member)
                .join(member.team, team)
                .groupBy(team.name)
                .fetch();
Tuple A = fetch.get(0);
Tuple B = fetch.get(1);

assertThat(A.get(team.name)).isEqualTo("team1");
assertThat(B.get(team.name)).isEqualTo("team2");
assertThat(A.get(member.age.avg())).isEqualTo(12.5);

GroupBy를 통해 팀 이름으로 묶어서 각 그룹의 멤버들 평균나이를 구하는 쿼리를 만드는 예제이다.

 

 

관련글

https://www.inflearn.com/course/Querydsl-%EC%8B%A4%EC%A0%84/dashboard

 

실전! Querydsl - 인프런 | 강의

Querydsl의 기초부터 실무 활용까지 한번에 해결, 본 강의는 자바 백엔드 개발의 실전 코스를 완성하는 마지막 강의 입니다. 스프링 부트와 JPA 실무 완전 정복 로드맵을 우선 확인해주세요. 로드

www.inflearn.com

 

 

 

 

'백엔드 > QueryDSL' 카테고리의 다른 글

QueryDSL - 동적 쿼리  (0) 2021.09.01
QueryDSL 프로젝션, DTO 사용  (0) 2021.09.01
쿼리 dsl 입문  (0) 2021.08.30