Querydsl 기본 문법 - 2

Hyeon·2023년 7월 28일
0

Querydsl

목록 보기
3/7

집합

집합 함수

List<Tuple> result = queryFactory
        .select(
                member.count(),
                member.age.sum(),
                member.age.avg(),
                member.age.max(),
                member.age.min()
        )
        .from(member)
        .fetch();

group by

List<Tuple> result = queryFactory
        .select(team.name, member.age.avg())
        .from(member)
        .join(member.team, team)
        .groupBy(team.name)
        .fetch();
}

having 절도 사용 가능하다.

조인

기본 조인

기본 조인

List<Member> result = queryFactory
        .selectFrom(member)
        .join(member.team, team)
        .where(team.name.eq("teamA"))
        .fetch();
}

세타 조인

세타 조인이란? 연관 관계가 없는 엔티티를 조인하는 것이다.
세타 조인을 사용할 경우, left outer join 이나 right outer join 이 불가능하다.
on 을 사용하면 가능하다.

List<Member> result = queryFactory
        .select(member)
        .from(member, team)
        .where(member.username.eq(team.name))
        .fetch();

on 절

join 대상 필터링

inner join 일 경우, where 절을 이용해도 결과가 동일하다.
inner join 이면 where 절을 이용하고, outer join 일 경우 on 절을 이용하자.

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

연관관계 없는 엔티티 외부 조인

하이버네이트 5.1부터 on 을 이용해 서로 관계가 없는 필드로 외부 조인이 가능하게 되었다.
일반 조인과 다르게 leftjoin 부분에 엔티티가 하나만 들어간다

  • 일반조인: leftJoin(member.team, team)
  • on조인: from(member).leftJoin(team).on(xxx)
List<Tuple> result = queryFactory
        .select(member, team)
        .from(member)
        .leftJoin(team).on(member.username.eq(team.name))
        .fetch();

페치 조인

  Member findMember = queryFactory
        .selectFrom(member)
        .join(member.team, team).fetchJoin()
        .where(member.username.eq("member1"))
        .fetchOne();

<참고>엔티티가 로딩되었는지 여부는 EntityManagerFactory를 이용하면 알 수 있다.

@PersistenceUnit
EntityManagerFactory emf;

// 이미 로딩됬으면 True 아니면 False
boolean loaded = emf.getPersistenceUnitUtil().isLoaded(findMember.getTeam());
assertThat(loaded).as("페이 조인 미적용").isFalse();

서브 쿼리

com.querydsl.jpa.JPAExpressions를 사용하면 된다.
(static import를 이용해 더 간결하게 만드는 게 가능하다!)

List<Member> result = queryFactory
        .selectFrom(member)
        .where(member.age.eq(
                        JPAExpressions
                                .select(memberSub.age.max())
                                .from(memberSub)
                )
        ).fetch();

select 절에서 서브 쿼리 사용

List<Tuple> result = queryFactory
              .select(member.username,
                      JPAExpressions
                              .select(memberSub.age.avg())
                              .from(memberSub)
              ).from(member)
              .fetch();

from 절에서 서브 쿼리

JPA JPQL 서브쿼리의 한계점으로 from 절에서 서브쿼리를 사용할 수 없다. 따라서 Querydsl 에서도 from 절에서 서브쿼리를 사용할 수 없다.

원래 select 절에도 서브 쿼리는 사용할 수 없다. 그러나 하이버네이트 구현체를 사용하는 경우, 서브 쿼리를 사용할 수 있다.

해결 방안

  1. 서브 쿼리를 join으로 변경한다. (가능한 상황 / 불가능한 상황 모두 존재)
  2. 애플리케이션에서 쿼리를 2번 분리해서 실행한다.
  3. nativeSQL을 사용한다.

Case 문

이런 로직은 가능하면 DB에서 처리하기 보다는, 애플리케이션 로직을 통해 처리하는 편이 더 바람직하다.

기본 Case 문

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

복잡한 Case 문

List<String> result = queryFactory
        .select(new CaseBuilder()
                .when(member.age.between(0, 20)).then("0~20살")
                .when(member.age.between(21, 30)).then("21~30살")
                .otherwise("기타")
        ).from(member)
        .fetch();

order by 에서 case 문 사용하기

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, member.age, rankPath)
        .from(member)
        .orderBy(rankPath.desc())
        .fetch();

상수, 문자 더하기

상수가 필요할 땐 Expressions.constant() 를 사용한다.

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

문자 더하기 concat

문자가 아닌 다른 타입들은 stringValue() 를 이용하면 된다. 특히 Enum 을 처리할 때 자주 사용한다.

//{username}_{age}
List<String> result = queryFactory
        .select(member.username.concat("_ ").concat(member.age.stringValue()))
        .from(member)
        .where(member.username.eq("member1"))
        .fetch();

출처

  • 인프런 김영한님의 실전! Querydsl 강의를 수강하며 정리한 내용입니다.
profile
컴공학부생입니다.

0개의 댓글