본문 바로가기
Java & Kotlin/Spring Data

[QueryDSL] QueryDSL 기본문법

by heekng 2022. 5. 11.
반응형

QueryDSL 기본문법

기본적인 조회

Member findMember = queryFactory
                .select(member)
                .from(member)
                .where(member.username.eq("member1"))
                .fetchOne();
  • QueryDSL을 이용한 기본적인 where절을 이용한 조회이다.
  • QMember와 같이 QType 클래스를 static import하여 사용하면 간결한 코드를 구성할 수 있다.
    • 별칭을 다르게 두어야 한다면 새로 선언하자.

검색조건

Member findMember = queryFactory
                .selectFrom(member)
                .where(member.username.eq("member1").and(member.age.between(10, 30)))
                .fetchOne();
  • where절에는 and나 or을 사용할 수 있다.
  • and 연산의 경우 .where(member.username.eq("member1"), member.age.between(10, 30))와 같이 ,를 이용해 간단하게 사용할 수도 있다.
    • 또한 해당 검색조건이 null일 경우 무시한다. 따라서 동적 쿼리를 깔끔하게 구성할 수 있다.
  • where절 안에는 여러 검색 조건이 사용 가능하다.
    • eq(): A = ?
    • ne(): A != ?
    • eq().not(): A != ?
    • isNotNull(): A is not null
    • in(): A in (?)
    • notIn(): A not in (?)
    • between(): A between ?, ?
    • goe(): A >= ?
    • gt(): A > ?
    • loe(): A <= ?
    • lt(): A < ?
    • like(): A like ?
    • contains(): A like "%?%"
    • startWith(): A like "?%?

결과조회

  • fetch(): 리스트를 조회한다, 값이 없을 때에는 빈 리스트가 반환된다.
  • fetchOne(): 단 건 조회
    • 결과가 없을 때에는 null을 리턴한다.
    • 결과가 둘 이상일 때에는 NonUniqueResultException이 발생한다.
  • fetchFirst(): limit(1).fetchOne()과 동일하다.
  • fetchResults(): 페이징 정보를 포함하여 total count쿼리를 추가로 실행시킨다.
    • 이후 getTotal()getResult()메서드로 정보를 조회할 수 있다.
  • fetchCount(): count쿼리로 변형해 count수를 조회한다.

페이징

QueryResults<Member> queryResults = queryFactory
                .selectFrom(member)
                .orderBy(member.username.desc())
                .offset(1)
                .limit(2)
                .fetchResults();
  • offset(): 시작점을 설정한다.
  • limit(): 최대 조회 수를 설정한다.
  • listResults(): QueryResults타입으로 리턴받는다.
    • QueryResults.getTotal(): 전체 수 조회
    • QueryResults.getLimit(): limit 조회
    • QueryResults.getOffset(): offset 조회
    • QueryResults.getResults(): 결과값 조회

정렬

  • 정렬은 orderBy를 사용한다.
  • asc(): 오름차순 정렬
  • desc(): 내읾차순 정렬
  • nullsLast(), nullsFirst: null값의 위치를 설정한다.
    • asc().nullsLast()와 같은 형태로 사용한다.

집합

List<Tuple> result = queryFactory
                .select(team.name, member.age.avg())
                .from(member)
                .join(member.team, team)
                .groupBy(team.name)
                .fetch();
  • JPQL이 제공하는 모든 집합 함수를 제공한다.
  • 집합 함수를 사용하면 tuple로 결과값이 리턴된다.
  • 함수
    • COUNT(): 개수
    • SUM(): 합
    • AVG(): 평균
    • MAX(): 최대
    • MIN(): 최소
  • groupBy(): 필드명을 이용해 그룹화한다.
  • having(): having절 사용

조인

List<Member> result = queryFactory
                .selectFrom(member)
                .join(member.team, team)
                .where(team.name.eq("teamA"))
                .fetch();
  • join은 .join(조인대상, 별칭쿼리타입)의 형태로 사용한다.
    • innerJoin(): sql의 innerJoin
    • leftJoin(): sql의 leftJoin
    • rightJoin(): sql의 rightJoin
    • fullJoin(): sql의 fullJoin
  • on(): join의 on절을 사용한다.
    • on절을 사용해 조인 대상을 필터링하는 것은 innerJoin사용시 where절로 필터링하는 것과 동일하다.
    • 내부조인이면 where을 사용하고, 외부조인인 경우에 사용한다.
  • fetch(): join에 페치조인을 적용한다.
    • innerJoin(~~).fetch()의 형태로 사용한다.

서브쿼리

QMember memberSub = new QMember("memberSub");

List<Member> result = queryFactory
        .selectFrom(member)
        .where(member.age.eq(
                JPAExpressions
                    .select(memberSub.age.max())
                    .from(memberSub)
        ))
        .fetch();
  • 서브쿼리는 JPAExpressions를 이용한다.
  • 주로 새로운 QType을 정의하여 사용한다.
  • static import를 이요하면 깔끔한 코드를 작성할 수 있다.
  • FROM절의 서브쿼리
    • JPA JPQL에서는 FROM절의 서브쿼리를 허용하지 않는다.
    • 따라서 서브쿼리를 join변경, 애플리케이션 쿼리 분리, nativeSQL을 사용하는 방안으로 해결해야 한다.

CASE문

List<String> result = queryFactory
            .select(member.age
                    .when(10).then("열살")
                    .when(20).then("스무살")
                    .otherwise("기타")
            )
            .from(member)
            .fetch();
  • when(): sql의 when
  • then(): when에 해당할 때
  • otherwise(): 나머지 상황

조건을 변수로 선언하기

NumberExpression<Integer> rankPath = new CaseBuilder()
             .when(member.age.between(0, 20)).then(2)
             .when(member.age.between(21, 30)).then(1)
             .otherwise(3);
  • 위와 같이 조건을 변수로 선언하여 실 코드에서 사용할 수 있다.

상수, 문자 더하기

List<Tuple> result = queryFactory
                .select(member.username, Expressions.constant("A"))
                .from(member)
                .fetch();

List<Tuple> result = queryFactory
                .select(member.username.concat("_").concat(member.age.stringValue()), member.age)
                .from(member)
                .where(member.username.eq("member1"))
                .fetch();
  • Expressions.constant(): 상수를 더할 때 사용한다.
  • concat(): 문자를 더할 떄 사용한다.

마침

대체적으로 SQL, JPQL의 문법을 따라가는 형태를 취한다.
그리고 복잡한 sql을 자바 코드로 사용한다는 것, 컴파일 단계에서 오류를 잡아낼 수 있다는 것은 굉장히 매력적인 것 같다.

반응형

'Java & Kotlin > Spring Data' 카테고리의 다른 글

[QueryDSL] 벌크연산과 SQL Funtion  (0) 2022.05.15
[QueryDSL] 동적쿼리  (0) 2022.05.14
[QueryDSL] 프로젝션  (0) 2022.05.14
[QueryDSL] QueryDSL 시작하기  (0) 2022.05.10
[JPA] UniqueConstraint와 Embedded field  (0) 2022.05.07
[JPA]영속성 전이 CASCADE  (0) 2022.04.21