본문 바로가기

개인적으로 공부한 것을 정리해 놓은 블로그입니다 틀린 것이 있으면 댓글 부탁 드립니다!


JPA/QueryDSL

QueryDSL 공부 1 - queryDSL 설정

반응형

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이 같은지 테스트해봤다 

 

테스트가 성공했다 . 

 

 

 

 

 

 

반응형