Building Jpa with Querydsl

Gradle 프로젝트 기준으로 JPA에 QueryDSL을 연동하는 방법을 알아본다.

build.gradle

QueryDSL은 QClass라는 객체를 자동으로 생성하고 이를 기반으로 타입 세이프한 쿼리를 작성할 수 있도록 돕는다. 이 QClass 객체들이 생성이 될 수 있도록 아래처럼 플러그인을 추가해줘야한다.

1
2
3
4
5
6
7
8
9

plugins {
...

id "com.ewerk.gradle.plugins.querydsl" version "1.0.10"
...

}

아래는 QueryDSL 의존성 추가하는 코드이다.

1
2
3
4
5
6
7
8
9

dependencies {
...

implementation 'com.querydsl:querydsl-jpa'

...
}

QueryDSL이 QClass를 만들 때 어느 경로에 생성할지와 같은 부가적인 설정 정보이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

def querydslDir = "$buildDir/generated/querydsl"

querydsl {
jpa = true
querydslSourcesDir = querydslDir
}

sourceSets {
main.java.srcDir querydslDir
}

configurations {
querydsl.extendsFrom compileClasspath
}

compileQuerydsl {
options.annotationProcessorPath = configurations.querydsl
}

test {
useJUnitPlatform()
}

여기까지 추가했다면 Gradle 탭을 열고 Gradle build를 하자. 그러면 위에서 설정한 경로에 QClass 파일이 생성될 것이다.
확인해보자.

QuerydslConfig.java

QueryDSL로 쿼리를 만들때 주로 사용하게 되는 객체는 JPAQueryFactory이다. 이 객체를 빈으로 등록하여 사용하자.

1
2
3
4
5
6
7
8
9
10

@Configuration
public class QuerydslConfig {
@PersistenceContext
private EntityManager entityManager;

@Bean
public JPAQueryFactory jpaQueryFactory() { return new JPAQueryFactory(entityManager); }
}

Entity

QueryDSL이 정상 동작하는지 확인하기 위해 샘플 Entity를 만든다.

Cell.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

@Slf4j
@Getter
@Setter
@ToString
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Cell {
public enum Type { Objective, Plan, Todo }

@Id
@GeneratedValue
protected Long id;

protected LocalDateTime startDateTime;

protected LocalDateTime endDateTime;

protected String status;

protected Type type;

@ManyToOne(cascade = CascadeType.PERSIST)
protected Member member;
}

Repository

QueryDSL이 정상 동작하는지 확인하기 위해 샘플 Repository 만든다. JpaRepository를 상속받는 메인 Repository를 만들고 Custom Repository를 만든다. 그 후에 Custom Repository의 구현체를 만들고 여기서 QueryDSL을 사용한다.

CellRepository.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

@Transactional
public interface CellRepository<T extends Cell> extends JpaRepository<T, Long>, CellRepositoryCustom<T> {
List<T> findByType(Cell.Type type);
}

public interface CellRepositoryCustom<T extends Cell> {
}

@RequiredArgsConstructor
public class CellRepositoryCustomImpl<T extends Cell> implements CellRepositoryCustom<T> {
private final JPAQueryFactory queryFactory;


}


You could use this repository when you need to create more complexible query. It’s operated by querydsl.

ObjectiveQueryRepository.java

1
2
3
4
5
6
7
8
9
10
11
12
13

@RequiredArgsConstructor
@Repository
public class ObjectiveQueryRepository {
private final JPAQueryFactory queryFactory;

public List<Objective> findByTitle(String title) {
return queryFactory.selectFrom(objective)
.where(objective.title.eq(title))
.fetch();
}
}

You can make a various queries using both method-query and querydsl.

Test

Finally we can use the querydsl.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

@SpringBootTest
class ObjectiveRepositoryTest {

@Autowired
private ObjectiveRepository objectiveRepository;

@Autowired
private ObjectiveQueryRepository objectiveQueryRepository;

@Test
void save() {
Objective obj = Objective.builder()
.title("title")
.priority(1)
.status(1)
.startDateTime(LocalDateTime.now())
.endDateTime(DateTimeUtil.of(2021, 4, 30))
.description("It's description")
.build();

objectiveRepository.save(obj);

List<Objective> result = objectiveQueryRepository.findByTitle("title");

System.out.println(result2);
}
}

Share