QueryDSL 은 JPA 를 사용할때 동적쿼리나 복잡한 쿼리들을 자바로 만들어 낼 수 있도록 도와주는 라이브러리이다.
쿼리가 자바로 작성되기 때문에 컴파일 시점에 오류를 잡아낼 수 있고 , 가독성 있게 작성 할 수 있는 것이 장점이다 .
설치를 해보고 QueryDSL이 어떻게 작동 하는지 알아보자
gradle 을 기준으로 설치를 해보려 한다 . spring initializer를 사용하여 프로젝트를 생성할 경우에 추가할 라이브러리 목록에 QueryDSL은 없기 때문에 따로 추가가 필요하다.
plugins {
id 'org.springframework.boot' version '2.5.1'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
}
group = 'com.queryDsl'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
developmentOnly 'org.springframework.boot:spring-boot-devtools'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'com.querydsl:querydsl-jpa'
}
test {
useJUnitPlatform()
}
//QueryDSL 설정 추가
//Q파일 생성 위치 설정
def querydslDir = "$buildDir/generated/querydsl"
//기본 설정들
querydsl {
jpa = true
querydslSourcesDir = querydslDir
}
sourceSets {
main.java.srcDir querydslDir
}
configurations {
querydsl.extendsFrom compileClasspath
}
compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}
위의 코드처럼 플러그인과 dependency를 추가해 준다.
QueryDsl 은 사용자가 정의한 엔티티에 QueryDsl을 적용하기 위해 Q파일이라 부르는 엔티티에 QueryDSL 기능들을 랩핑한 클래스를 만들어내고 이를 기반으로 작동한다.
(예를 들어 Member 라는 엔티티가 있다면 QMember 라는 식으로 파일을 만들어 낸다. )
위와 같은 동작들을 가능하게 하기 위해서 QueryDSL 자체의 설정이 필요하다 위의 코드에서는 //QueryDSL 설정 추가 아래의 코드들이 그것이다.
설정에 는 Q파일 생성위치나 , queryDsl의 기본 설정들이 들어 있다
위의 설정 후에 gradle 을 리프레쉬 하면
gradle의 task에 other에 queryDSL에 관한 것들이 추가 된 것을 알 수 있다 .
compileQueryDsl을 하면 쿼리 dsl 이 프로젝트에서 @Entity가 있는 클래스를 찾아 Q파일을 생성해준다
package com.querydsl.study.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Test {
@Id
@GeneratedValue
private Long id;
}
간단하게 Test 라는 엔티티를 만들고 compildeQueryDsl을 실행시켰다.
설정 해놓은 경로에 QTest라는 Test 클래스에대한 Q파일이 생성되었다 .
package com.querydsl.study.domain;
import static com.querydsl.core.types.PathMetadataFactory.*;
import com.querydsl.core.types.dsl.*;
import com.querydsl.core.types.PathMetadata;
import javax.annotation.Generated;
import com.querydsl.core.types.Path;
/**
* QTest is a Querydsl query type for Test
*/
@Generated("com.querydsl.codegen.EntitySerializer")
public class QTest extends EntityPathBase<Test> {
private static final long serialVersionUID = 940717515L;
public static final QTest test = new QTest("test");
public final NumberPath<Long> id = createNumber("id", Long.class);
public QTest(String variable) {
super(Test.class, forVariable(variable));
}
public QTest(Path<? extends Test> path) {
super(path.getType(), path.getMetadata());
}
public QTest(PathMetadata metadata) {
super(Test.class, metadata);
}
}
QTest를 보면 EntityPathBase를 상속받아서 구현되어 있고 EntityPathBase를 통해 부모인 Test 클래스를 맵핑하고 있다.
참고로 위와 같은 Q파일들은 프로젝트를 계속 만들어내는 동안에 바뀔 수 있기 떄문에 Git Ignore 해주는 것이 좋다 .
하지만 위 방법으로 할 경우에 보통 Build 폴더는 기본적으로 Ignore 하기 떄문에 따로 설정을 할 필요는 없다 .
QTest가 작동하는지 Test 해보자
음 테스트를 해보려니 @Test랑 Test이름이 겹쳐 버려 Member라는 엔티티를 만들어서 테스트를 진행해 봤다.
Q파일이 작동하는지만 알아보려고 contextLoads 안에서 테스트 해봤다.
@SpringBootTest
@Transactional
class StudyApplicationTests {
@Autowired
EntityManager em;
@Test
void contextLoads() {
Member member = new Member();
em.persist(member);
JPAQueryFactory queryFactory = new JPAQueryFactory(em);
QMember qMember = new QMember("m");
Member member1 = queryFactory
.selectFrom(qMember)
.fetchOne();
Assertions.assertThat(member1).isEqualTo(member);
}
}
QueryDSL은 query를 빌드하기 위한 것이지 JPA 영속성 컨텍스트에서 관리되거나 하는 것이 아니다
위처럼 멤버를 생성하여 저장하고
QueryDsl에서 제공하는 JPAQueryFactory에 파라미터로 엔티티 매니저를 넘기고
간단하게 member를 가져오는 코드를 작성했다 .
위의 코드를 JPQL로 생각하면 "select m from Member m" 일 것이다 .
(JPAQueryFactory의 메서드들의 파라미터는 EntityPath<T>타입 으로 되어있기 때문에 Q파일을 사용해야한다 일반 엔티티는 사용 못한다)
member 와 member1이 같은지 테스트해봤다
테스트가 성공했다 .
'JPA > QueryDSL' 카테고리의 다른 글
QueryDSL 공부 4 - QueryDSL 활용2 (join문) (0) | 2021.06.19 |
---|---|
QueryDSL 공부 3 - QueryDSL 활용1 (0) | 2021.06.18 |
QueryDSL 공부 2 - Q-Type 활용 (0) | 2021.06.18 |
Spring boot -QueryDSL 과 JPQL 차이점 (0) | 2020.11.27 |
Spring boot 프로젝트에 QueryDSL 설정 및 검증 (0) | 2020.11.27 |