개발놀이터

Querydsl 기본문법 본문

JPA/QueryDSL

Querydsl 기본문법

마늘냄새폴폴 2021. 10. 1. 21:19

*QueryDSL

*QueryDSL 시작하기

  1. build.gradle plugins에 id "com.ewerk.gradle.plugins.querydsl"version "1.0.10" 추가
  2. build.gradle dependencies 에 implementation 'com.querydsl:querydsl-jpa' 추가
  3. build.gradle에 맨아래에
    def querydslDir = "$buildDir/generated/querydsl"

querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
configurations {
querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
추가

  1. 엔티티가 하나 추가될 때 마다 오른쪽 위에 gradle > other > compileQuerydsl 실행 = build > generated 에 Q타입이 만들어짐
  2. JPAQueryFactory queryFactory = new JPAQueryFactory(em); 추가 -> 전역변수로 빼도 된다. (동시성 문제 걱정없음)

*JPQL vs QueryDSL
-member1을 찾아라
JPQL : em.createQuery("select m from Member m where m.username = :username, Member.class).setParameter("username", "member1"). getSingleResult();
QueryDSL : queryFactory.select(QMember.member).from(QMember.member).where(QMember.member.username.eq("member1")).fetchOne();

QMember는 static import 할 수 있음 = queryFactory.select(member).from(member).where(member.username.eq("member1")).fetchOne();

*Where 절에 여러개 파라미터가 오면 어떻게 해야할까?
queryFactory.selectFrom(member).where(member.username.eq("member1").and(member.age.eq(10)).fetchOne();
queryFactory.selectFrom(member).where(member.username.eq("member1"), member.age.eq(10)).fetchOne();
둘 다 가능

*최종연산 (fetch)

  1. List fetch = queryFactory.selectFrom(member).fetch();
  2. Member fetchOne = queryFactory.selectFrom(member).fetchOne();
  3. Member fetchFirst = queryFactory.selectFrom(member).fetchFirst();

*정렬 (sorting)
queryFactory.selectFrom(member).where(member.age.eq(100)).orderBy(member.age.desc(), member.username.asc()).fetch();

*페이징 (paging)
queryFactory.selectFrom(member).orderBy(member.username.desc()).offset(1).limit(2).fetch(); -> size() = 2

*기본조인
조인의 기본 문법은 첫 번째 파라미터에 조인 대상을 지정하고, 두 번째 파라미터에 엘리어스로 사용할 Q타입을 지정하면 된다.
queryFactory.selectFrom(member).join(member.team, QTeam.team).where(team.name.eq("teamA")).fetch();


위의 기본 조인은 연관관계매핑이 된 엔티티끼리의 조인이고 연관관계 매핑이 안된 엔티티끼리의 조인을 할 수 있는데 이를 세타조인이라 한다.
queryFactory.select(member).from(member, team)

*on절

  1. 조인 대상 필터링
    queryFactory.select(member, team).from(member).leftjoin(member.team, team).on(team.name.eq("teamA")).fetch();

cf) 조인 대상을 필터링 할 때 내부조인을 사용하게 되면 on절을 사용하는 것이나 where절을 사용하는 것이나 차이가 없다. 따라서 on절을 활용한 조인 대상 필터링을 사용할 때 내부조인이라면 익숙한 where절을 사용하고 정말 외부조인이 필요한 경우에만 on절을 사용하는 것이 가독성을 높이는데에 도움이 된다.

  1. 연관관계 없는 엔티티 외부 조인 (문법이 살짝 다르다)
    queryFactory.select(member, team).from(member).leftjoin(team).on(member.username.eq(team.name)).fetch();

*페치조인
기본 조인과 문법은 비슷하지만 join 뒤에 fetchJoin()을 붙여준다.
queryFactory.selectFrom(member).join(member.team, team).fetchJoin().where(member.username.eq("member1")).fetchOne();

*서브쿼리
com.querydsl.jpa.JPAExpressions 사용 -> static import 할 수 있음
queryFactory.selectFrom(member).where(member.age.eq(JPAExpressioins.select(memberSub.age.max()).from(memberSub))).fetch();

JPA에서는 from절 서브쿼리는 지원하지 않는다. from절 서브쿼리를 사용해야 한다면 다음을 시도해보면 좋을 것이다.

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

*case문

queryFactory.select(member.age.when(10).then("열살").when(20).then("스무살").otherwise("기타")).from(member).fetch();

SQL은 단순히 데이터를 퍼 올리는데에만 사용하는 것이 좋고 데이터를 가공하는 것은 애플리케이션 레벨에서 하면 좋다. case문이 꼭 필요한 상황이 살다보면 있을테지만 굳이 case문을 사용하는 상황은 피해야 할 것이다.

*concat문
queryFactory.select(member.username.concat("_").concat(member.age.stringValue())).from.where(member.username.eq("member1")).fetch();

문자가 아닌 다른 타입들은 stringValue로 문자로 변환할 수 있다. 이 방법은 enum타입을 처리할 때도 자주 사용한다.

'JPA > QueryDSL' 카테고리의 다른 글

스프링 부트 5.0 Querydsl 설정 변경  (0) 2023.05.30
QueryDSL 중급문법  (0) 2022.02.07
QueryDSL 기본문법  (0) 2022.02.07
Querydsl 실무활용  (0) 2021.10.01
Querydsl 중급문법  (0) 2021.10.01