[Querydsl] querydsl 학습_3

2020. 9. 4. 18:59개발/DBMS

반응형

[3주차]

 

중급문법 ( JOIN, DTO 조회, 동적쿼리)

 

 

1. JOIN

  • 조인 문법을 사용하여 연관 관계가 있는 ENTITY 혹은 연관 관계가 없는 ENTITY 간 조인이 가능하다

1-1. 연관 관계가 있는 ENTITY

 

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

 

1-2. 연관 관계가 없는 ENTITY

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

 

JOIN 문법

문법 기능

join(), innerJoin()

내부 조인

leftJoin()

left 외부 조인

rightJoin()

right 외부 조인

fetchJoin()

성능 최적화 (N +1 문제 해결 방법 중 한개)

 

 

2. SUBQUERY

  • com.querydsl.jpa.JPAExpressions 를 사용 하여 subQuery가 가능하다.

  • 단, 해당 기능에는 단점 도 존재한다. 그것 은 바로 subQuery를 쓸 수 있는 곳이 한정 적이다.

    • 가능한 곳: select, where

    • 불가능한 곳: from

  • subquery 가 안되는 곳에서의 대처법

    • 서브쿼리를 JOIN으로 변경한다

    • 쿼리를 분리해서 실행한다

    • nativeSQL를 사용한다(비추)

2-1. where 절의 subQuery

Member findMember = queryFactory
    .selectFrom(member)
    .where(member.age.eq(
        JPAExpressions.select(memberSub.age.max()).from(memberSub)
    ))
    .fetchOne();

 

2-2. select 절의 subQuery

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

 

 

3. CASE 문

  • .when().then().otherwise() 사용 하여 간단히 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();

 

CASE 문법

문법 기능

.when()

조건

.then()

.when()의 조건을 만족했을때 나오는 값

.otherwise()

.조건에 만족하는 값 외 것은 나타는 값

 

4. DTO 조희

  • ENTITY의 값을 그대로 가져오지 않고 중간 객체를 지정하여 가져 올 수도 있다.

  • DTO 조회 방법

4-1. JPQL 를 사용 한 경우

List<MemberDto> result = em.createQuery(
    "select new me.study.querydslsample.dto.MemberDto(m.username, m.age) " +
        "from Member m", MemberDto.class)
    .getResultList();

 

4-2. 프로퍼티(setter) 사용 한 경우

List<MemberDto> result = queryFactory
    .select(Projections.bean(MemberDto.class,
        member.username, member.age))
    .from(member)
    .fetch();

 

4-3. 필드를 사용 한 경우

List<MemberDto> result = queryFactory
    .select(Projections.fields(MemberDto.class,
        member.username, member.age))
    .from(member)
    .fetch();

 

4-4. 생성자를 사용 한 경우

List<MemberDto> result = queryFactory
    .select(Projections.constructor(MemberDto.class,
        member.username, member.age))
    .from(member)
    .fetch();

 

4-5. QueryProjection 를 사용 한 경우

  • 사전 준비 가져올 DTO에 어노테이션 기반의 생성자를 만들어 줘야한다.

@QueryProjection를 사용 하여 생성자 생성

import com.querydsl.core.annotations.QueryProjection;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@NoArgsConstructor
public class MemberDto {

  private String username;
  private int age;

  @QueryProjection
  public MemberDto(String username, int age) {
    this.username = username;
    this.age = age;
  }
}

실 사용

List<MemberDto> result = queryFactory
    .select(new QMemberDto(member.username, member.age))
    .from(member)
    .fetch();

 

DTO 를가져오는 다양한 방법

문법 기능 특징

Projections.bean(클래스,컬럼)

프로퍼티(setter) 사용

 

Projections.fields(클래스,컬럼)

필드를 사용

 

Projections.constructor(클래스,컬럼)

생성자 사용

 

new QClassName(컬럼)

QueryProjection 사용

장점

  • DTO 로 가져올때 컬럼 타입, 숫자등을 안전 하게 가져 올 수 있다.

단점

  • DTO 용 QClass를 생성 필요

  • DTO 가 querydsl의 의존 관계가 생김

 

5. 동적 쿼리

  • querydsl 를 사용하면 복잡한 동적 쿼리를 매우 간편하게 작성 가능하다. 개인적으로 querydsl 의 가장 큰 장점으로 생각한다.

5-1. BooleanBuilder 를 사용하는 방법

  • 자바 코드 짜듯이 간편하게 사용할 수있다.

private List<Member> searchMember(String username, Integer age) {

    BooleanBuilder builder = new BooleanBuilder();
    if (username != null) {
      builder.and(member.username.eq(username));
    }

    if (age != null) {
      builder.and(member.age.eq(age));
    }

    return queryFactory
        .selectFrom(member)
        .where(builder).fetch();
  }

 

5-2. BooleanExpression 를 사용하는 방법

  • 해당 부분은 5-1 보다 더 자바 코드 처럼 짤 수있는 방법으로 각 조건을 메소드화 하여 사용 하는 방법이다. (이 방법을 추천한다)

  • 이 방법으로 사용하면 핵심 비지니스 로직을 확인하는데 용이하다.

private List<Member> searchMember(String username, Integer age) {
  return queryFactory
      .selectFrom(member)
      .where(usernameEq(username), ageEq(age))
      .fetch();
}

private BooleanExpression ageEq(Integer age) {
  return age != null ? member.age.eq(age) : null;
}

private BooleanExpression usernameEq(String username) {
  return username != null ? member.username.eq(username) : null;
}

private BooleanExpression allEq(String username, Integer age) {
  return usernameEq(username).and(ageEq(age));
}

 

[3주차]-END

참고: www.inflearn.com/course/Querydslwww.inflearn.com/course/Querydsl-%EC%8B%A4%EC%A0%84

 

실전! Querydsl - 인프런

Querydsl의 기초부터 실무 활용까지 한번에 해결 중급이상 웹 개발 데이터베이스 서버 개발 Back-End Java JPA Spring Data JPA JQuery 온라인 강의 쿼리, JSP, 실전 Querydsl, 김영한 강의, jpa 강의

www.inflearn.com

 

반응형

'개발 > DBMS' 카테고리의 다른 글

[Querydsl] querydsl 학습_4  (0) 2020.11.23
[Querydsl] querydsl 학습_2  (0) 2020.08.28
[Querydsl] querydsl 학습_1  (0) 2020.08.19
[Querydsl] querydsl 적용시 주의점  (1) 2019.11.08