개발놀이터
Querydsl 기본문법 본문
*QueryDSL
*QueryDSL 시작하기
- build.gradle plugins에 id "com.ewerk.gradle.plugins.querydsl"version "1.0.10" 추가
- build.gradle dependencies 에 implementation 'com.querydsl:querydsl-jpa' 추가
- 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
}
추가
- 엔티티가 하나 추가될 때 마다 오른쪽 위에 gradle > other > compileQuerydsl 실행 = build > generated 에 Q타입이 만들어짐
- 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)
- List fetch = queryFactory.selectFrom(member).fetch();
- Member fetchOne = queryFactory.selectFrom(member).fetchOne();
- 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절
- 조인 대상 필터링
queryFactory.select(member, team).from(member).leftjoin(member.team, team).on(team.name.eq("teamA")).fetch();
cf) 조인 대상을 필터링 할 때 내부조인을 사용하게 되면 on절을 사용하는 것이나 where절을 사용하는 것이나 차이가 없다. 따라서 on절을 활용한 조인 대상 필터링을 사용할 때 내부조인이라면 익숙한 where절을 사용하고 정말 외부조인이 필요한 경우에만 on절을 사용하는 것이 가독성을 높이는데에 도움이 된다.
- 연관관계 없는 엔티티 외부 조인 (문법이 살짝 다르다)
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절 서브쿼리를 사용해야 한다면 다음을 시도해보면 좋을 것이다.
- 서브쿼리를 join으로 변경한다. (가능한 상황도 있고, 불가능한 상황도 있다.)
- 애플리케이션에서 쿼리를 2번 분리해서 실행한다.
- 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 |