JPQL은 검색에 대한 null 처리가 너무 복잡하기 때문에 검색 쿼리에 대한 더 좋은 유지관리를 위해 QueryDSL을 사용한다.
QueryDSL 설정하기
- 먼저, QueryDSL에 대한 라이브러리를 추가한다. (gradle방식)
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta' annotationProcessor "com.querydsl:querydsl-apt:5.0.0:jakarta" annotationProcessor "jakarta.annotation:jakarta.annotation-api" annotationProcessor "jakarta.persistence:jakarta.persistence-api"- Q클래스를 저장할 공간 지정을 위한 설정을 추가 한다.
def querydslDir = "$buildDir/generated/querydsl" sourceSets { main.java.srcDirs += [ querydslDir ] } tasks.withType(JavaCompile) { options.generatedSourceOutputDirectory = file(querydslDir) } clean.doLast { file(querydslDir).deleteDir() }
- Qclass생성을 위해 Gradle task에서 해당 프로젝트의 build파일을 실행해준다.
- 다음과 같은 build폴더가 생기면 QueryDSL을 작성할 준비가 된거다!!
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QMember m = new QMember("m");QMember m = QMember.m;import static 구문으로 변수를 직접 지정할 수도 있다.import static com.codingbox.querydsl.entity.QMember.*;select m from Member m where m.username = :username
과 같은 쿼리는 아래와 같이 표현할 수 있다.
queryFactory.select(member)
.from(member)
.where(member.username.eq("member1"))
.fetchOne();
.select(member)하는 대상과 .from(member)하는 대상이 동일하면, .selectFrom(member)이 가능하다.| SQL | QueryDSL |
|---|---|
| AND절 | .and() (또는, and()를 콤마(,)로 구분가능하다) |
| order by asc, order by desc절 | .orderBy(필드값.desc()나 .asc()) |
| null은 마지막에 위치 | .nullsLast() |
| group by절 | .groupBy() |
| having 조건절 | .having() |
| left outer join절 | .leftJoin("조인객체","객체이름").on("조인되는필드값") |
| inner join절 | .join().on() |
| IN절 | .in() |
| concat절 | .concat("") |
fetch() : 리스트로 조회fetchOne() : 단 건으로 조회.offset() : JPQL의 setFirstResult(), 해당 인덱스부터 조회.limit() : JPQL의 setMaxResults(), 해당 건까지 조회jpql의 count(*), sum(m.age), avg(m.age), max(m.age), min(m.age)등 집계함수에 대한 처리는 queryDSL에서도 Tuple이라는 라이브러리를 사용하면 가능하다.
select count(m), sum(m.age), avg(m.age), max(m.age), min(m.age) from Member m
JPAExpressions로 서브 쿼리문으로 활용queryFactory.selectFrom(member)
.where(member.age.eq(
JPAExpressions.select(memberSub.age.max())
.from(memberSub)
))
| when ~ then문 | .when(조건).then("값").otherwise("기타 값") |
new CaseBuilder() 객체를 통해 생성할 수 있다.Projections객체를 활용하여 bean, fields, 생성자를 조회할 수 있다. .select(Projections.bean(MemberDTO.class, member.username, member.age))
.as()를 붙혀 이름을 동일하게 변경한다.).select(Projections.fields(MemberDTO.class, member.username, member.age))
.select(Projections.fields(UserDTO.class, member.username.as("name"), member.age))
.select(Projections.constructor(MemberDTO.class, member.username, member.age))