QueryDSL 문법

조건 쿼리

import static com.example.querydsl.entity.QMember.member

public List<Note> findAllMemberByNameAndAge(String username, Integer age) {
        return jpaQueryFactory.selectFrom(member)
                .where(member.username.eq(username)
                		.and(member.age.eq(age)))
                .fetch();
}

 

  • 검색 조건을 추가(and, or)할 때 체인 형식으로 합니다.
  • 파라미터로 null 값이 들어오면 해당

 

문법

member.username.eq("member")		// username = "member"
member.username.ne("member")		//username != "member"
member.username.eq("member").not()	// username != "member"
member.username.isNotNull()	//이름이 is not null

member.username.like("member%")       // like 검색
member.username.contains("member")	  // like :%member%: 검색
member.username.startsWith("member")  // like :member%: 검색

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


// 쉼표를 구분자로 파라미터를 추가하는 것은 and()와 같음
where(member.username.eq(username), member.age.eq(age))

 


 

결과 조회

  • fetch()
    • 리스트를 조회
    • 데이터가 없으면 빈 리스트 (NOT NULL)
  • fetchOne()
    • 단 한건 조회
    • 데이터가 없으면 Null 조회
    • 결과가 둘 이상이면 com.querydsl.core.NonUniqueResultException 예외 발생
  • fetchFirst()
    • 첫 번째로 발견되는 결과를 조회
    • limit(1).fetchOne()과 동일

 


 

정렬

  • orderBy()를 통한 정렬
    • asc() : 오름차순
    • desc() : 내림차순
    • nullsFirst() : null 데이터인 경우 처음에 결과 출력
    • nullsLast() : null 데이터인 경우 마지막에 결과 출력

 

    List<Member> result = jpaQueryFactory
            .selectFrom(member)
            .where(member.age.between(20,30))
            .orderBy(member.age.desc(), member.username.asc().nullsLast())
            .fetch();

 


 

페이징

페이지 조회 제한

    List<Member> result = queryFactory
            .selectFrom(member)
            .orderBy(member.username.asc())
            .offset(0) // 0부터 시작
            .limit(5)  //
            .fetch();

 


 

집합

  • count() : 카운트 수
  • sum() : 합
  • avg() : 평균
  • max() : 최댓값
  • min() : 최솟값
    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(10);
    assertThat(tuple.get(member.age.sum())).isEqualTo(100);
    assertThat(tuple.get(member.age.avg())).isEqualTo(10);
    assertThat(tuple.get(member.age.max())).isEqualTo(10);
    assertThat(tuple.get(member.age.min())).isEqualTo(10);
  • select 해서 가져오는 데이터가 하나인 경우 타입을 명확하게 지정할 수 있지만 타입이 둘 이상이라면 Tuple이나 DTO로 조회해야 한다.
    • Tuple은 QueryDsl에서 제공하는 자료구조입니다.
  • Tuple로 뽑을 수도 있지만 DTO로 가져올 수도 있습니다.

 

그룹화

  • groupBy() 
  • having()
    List<Tuple> result = jpqQueryFactory
            .select(team.name, member.age.avg())
            .from(member)
            .join(member.team, team)
            .groupBy(team.name)
            //.having(member.age.avg().gt(20))
            .fetch();

    for (Tuple tuple : result) {
        System.out.println("tuple = " + tuple);
    }

    Tuple teamA = result.get(0);
    Tuple teamB = result.get(1);

    assertThat(teamA.get(team.name)).isEqualTo("teamA");
    assertThat(teamA.get(member.age.avg())).isEqualTo(10);
    assertThat(teamB.get(team.name)).isEqualTo("teamB");
    assertThat(teamB.get(member.age.avg())).isEqualTo(20);
    
    
    
    / * *
      * tuple = [teamA, 10.0]
      * tuple = [teamB, 20.0]
      * /

 


 

조인

조인

  • join() / innerJoin()
  • leftJoin()
  • rightJoin()
    List<Member> result = jpqQueryFactory
            .selectFrom(member)
            .join(member.team, team)
            .where(team.name.eq("TeamA"))
            .fetch();
            
    // on절 사용
	List<Tuple> result = queryFactory
            .select(member, team)
            .from(member)
            .leftJoin(member.team, team)
            .on(team.name.eq("TeamA"))
            .fetch();
  • join의 첫 번째 파라미터
    • join 대상을 지정합니다.
    • 위 예시 경우, member가 가진 FK를 통해 조인을 합니다. leftJoin(member.team, team)
    • 아래 예시 경우, 연관관계가 없는 엔티티를 외부 조인하기 때문에 바로 엔티티를 적어줍니다. leftJoin(team)
      전달인자가 달라짐에 주의하자
  • join의 두 번째 파라미터
    • 첫 번째 파라미터의 별칭을 지정합니다.
  • join 뒤에 on절 사용도 가능합니다.

 

    List<Tuple> result = jpaQueryFactory
            .select(member,team)
            .from(member)
            .leftJoin(team)
            .on(member.username.eq(team.name))
            .fetch();

 

 

세타 조인

    List<Member> result = jpaQueryFactory
            .select(member)
            .from(member, team)
            .where(member.username.eq(team.name))
            .fetch();
  • from에 여러 엔티티를 지정하면 됩니다.

 

 

페치 조인

    Member findMemberByUsername = jpaQueryFactory
            .selectFrom(QMember.member)
            .join(member.team, team).fetchJoin()
            .where(QMember.member.username.eq(username))
            .fetchOne();
  • JPA에서 성능 최적화를 위해 사용하는 페치 조인 fetchJoin()

 


 

서브 쿼리

  • JPAExpressions을 이용하여 서브쿼리를 작성합니다.
  • JPA JPQL에서는 from 절의 서브쿼리를 지원하지 않기 때문에 QueryDSL도 지원하지 않습니다.
    // 서브쿼리를 만들때 alias가 중복되면 안되기 때문에 QMember를 따로 만들어주었습니다.
    QMember qMember = new QMember("m");
    
    
    // 나이가 가장 많은 회원
    Member findOldMember = jpaQueryFactory
            .selectFrom(member)
            .where(member.age.eq(
                    JPAExpressions
                            .select(qMember.age.max())
                            .from(qMember)

            ))
            .fetchOne();
            
	// 나이가 평균 이상이 회원들
    List<Member> findMembers = jpaQueryFactory
            .selectFrom(member)
            .where(member.age.goe(
                    JPAExpressions
                            .select(qMember.age.avg())
                            .from(qMember)

            ))
            .fetch();

 


 

Case 문

	List<String> result = jpaQueryFactory
            .select(member.age
                    .when(10).then("열살")
                    .when(20).then("스무살")
                    .when(30).then("서른살")
                    .otherwise("기타"))
            .from(member)
            .fetch();

 

  • CaseBuilder() 이용하여 작성하는 방법
    List<String> result = jpaQueryFactory
            .select(new CaseBuilder()
                    .when(member.age.between(0, 13)).then("어린이")
                    .when(member.age.between(14, 19)).then("청소년")
                    .otherwise("성인")
            )
            .from(member)
            .fetch();

 

  • case문 응용 - orderyBy 접목
나이가 0~30이 아닌 경우
나이가 0~20인 경우
나이가 21~30인 경우
→ 순서대로 출력
    NumberExpression<Integer> rankCase = new CaseBuilder()
            .when(member.age.between(0, 20)).then(2)
            .when(member.age.between(21, 30)).then(1)
            .otherwise(3);

    List<Tuple> result = jpaQueryFactory
            .select(member.username, member.age, rankCase)
            .from(member)
            .orderBy(rankCase.desc())
            .fetch();