JPAQueryFactory를 사용하기에 앞서 JPA와 Querydsl에 대해 자세히 알고 설명을 이어가고자 한다.
자바 ORM 기술 표준으로 POJO객체와 DB 데이터 간의 매핑을 처리하기 위한 ORM 표준을 의미한다. 즉 다시말해 정리하자면 JPA 자바 객체와 실제 테이블을 연결해주는 역할을 한다.
Querydsl은 JPQL 쿼리를 개발자가 보다 쉽고 빠르게 작성할 수 있도록 도우움을 주는 도구이다.
//JPQL
String username = "java";
String jpql = "select m from Member m where m.username = :username";
List<Member> result = em.createQuery(query, Member.class).getResultList();
jpql은 jpql문법을 모르면 쿼리를 작성하는데 어려움이 있다.
//QueryDSL
String username = "java";
List<Member> result = queryFactory
.select(member)
.from(member)
.where(usernameEq(username))
.fetch();
Querydsl은 @Entity가 붙어 Spring boot의 관리를 받는 엔터티들의 Meta 정보가 담긴 QClass를 만들고 이를 이용하여 query문을 작성한다. 해당 Querydsl query를 작성하면 자동으로 JPQL로 번역이 된다.
JPAQueryFactory란 JPA의 엔터티를 이용하여 JPQLQuery를 보다 쉽고 편리하게 작성할 수 있는 QueryDsl의 도구라 할 수 있다.
//Qclass가 생성될 곳을 정의한다.
def querydslSrcDir = 'src/main/generated'
sourceSets {
main {
java {
srcDirs += [ querydslSrcDir ]
}
}
}
dependencies{
...
// JPA 설정
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
// QueryDsl 설정
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
implementation "com.querydsl:querydsl-codegen:5.0.0" // QueryDSL 코드 생성
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
//Jakarta 설정 어노테이션에 사용된다.
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
...
import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceContext;
//해당 클래스가 설정과 관련된 class임을 spring boot에 알림
@Configuration
//@Entity로 관리되는 JPA 엔터티들의 상태 변화를 감시하는 기능을 킨다는 뜻
@EnableJpaAuditing
public class JPAConfig {
//@PersistenceContext는 EntityManager에 의존성 주입을 담당하는 Annotation이다.
@PersistenceContext
//EntityManager는 JPA에서 엔터티의 생성, 조회, 수정 삭제를 수행하는 객체이다
private EntityManager em;
@Bean
public JPAQueryFactory jpaQueryFactory(EntityManager em){
//쿼리를 작성하는 JPAQueryFactory에 EntityManager를 넘겨 사용한다.
return new JPAQueryFactory(em);
}
}
먼저 구조는 크게
select(Qclass / Projection)
.from(Qclass)
.where(조건절)
.fetch();
이다.
selectFrom(Qclass)
는
select(Qclass)
.from(Qclass)
와 동일하다.
만약 모든 필드를 사용하지 않고 다른 필드드를 사용한다 하면 Projection을 사용하면된다.
select(Projections.fields(정보를 담을 클래스.class, Qclass.가져올 필드1,Qclass.가져올 필드2...)
를 사용하면된다.
이때 만약 정보를 담을 클래스의 멤버변수의 이름과 가져올 필드명이 일치해야한다.
저건절은 Qclass에서 제공하는 조건식을 사용하면된다.
ex) Qclass.필드.조건