⚡ 개요
이번에는 QueryDsl에서 DateType을 사용하는 방법에 대해서 정리를 해보려고 한다.
QueryDsl을 사용하면서 Projections을 통해 쿼리 결과를 DTO 클래스로 변환해서 반환을 받고 리턴을 하는 경우가 종종 있다.
이때 조회 Entity 의 타입이 Date Type인 경우 변환을 할때 타입 에러가 발생하게 된다.
우리의 경우 데이터를 조회할때 예를 들어 1000개의 데이터중 필요한 Entity를 조회 해서 DTO로 변환을 하는 작업을 한다. 데이터의 양이 적다면 속도적인 측면에서 크게 문제가 되지 않지만 이력쪽 데이터를 조회하는 경우에는 속도적인 측면에서 많은 저하가 발생을 하게 되었다. 또한 데이터가 적더라도 컬럼의 타입 그대로가 아닌 변환을 해서 사용 해야하는 경우에도 Entity를 조회 해서 DTO로 변환을 하는 작업을 하게 되는 경우 매우 귀찮음이 발생하게 되었다. 이제 어떻게 해결을 했는지 정리를 해보려고 한다.
먼저 Expressions에 대해서 설명 하도록 하겠다.
⚡Expressions
Expressions는 Querydsl 타입 안전한 쿼리 API에서 사용되는 핵심 클래스 중 하나이다. Expressions 클래스는 다양한 데이터 타입에 대한 쿼리 표현식을 생성하는 메서드를 제공한다.
Expressions에서 제공하는 메서드는 다양한 데이터 타입에 대한 표현식을 생성할 수 있도록 구성되어 있다.
- numberExpression() : 숫자 데이터 타입에 대한 표현식을 생성
- stringExpression(): 문자열 데이터 타입에 대한 표현식을 생성
- booleanExpression(): 부울 데이터 타입에 대한 표현식을 생성
- comparableExpression(): Comparable 데이터 타입에 대한 표현식을 생성
- dateTimeExpression()❗ : 날짜 및 시간 데이터 타입에 대한 표현식을 생성
- entityPath(): 엔티티 데이터 타입에 대한 표현식을 생성
📒 날짜 및 시간 데이터 타입에 대한 표현식을 어떻게 사용했는지 정리
기본적인 내용을 설명 하자면 DB는 MariaDB를 사용하고 있으며, DTO 클래스에서 날짜를 반환 받을때 LocalDateTime, LocalDate, LocalTime 포맷으로 반환을 받고 있다.
// Dto
public class TestDto {
private Long rowNum;
private LocalDateTime testDateTime;
private LocalDate testDate;
private LocalTime testTime;
}
// sample
public class TestSample {
queryFactory
.select(
Projections.fields(
Test.class,
QTestTable.testTable.sample_dateTime.as("testDateTime"),
QTestTable.testTable.sample_date.as("testDate"),
QTestTable.testTable.sample_time.as("testTime"),
)
.from(QTestTable.testTable)
.fetch();
}
위의 내용처럼 DTO 클래스를 조회한다고 할때, dateFormatException()이 발생하게 될것이다.
java.sql.Timestamp 타입을 java.time.LocalDate로 변환하지 못해서 생기는 이슈이다. 이부분을 해결 하려면 조회 할때 타입을 변환해서 받아야 한다. 이때 사용한것이 Expressions의 DateTimeTemplate 이다. DateTimeTemplate은 날짜 및 시간 값을 처리하는 Expression을 생성하는 데 사용된다. 날짜 및 시간 값은 다양한 형식으로 저장될 수 있으며, DateTimeTemplate은 이러한 값들을 일관된 형식으로 처리할 수 있게 해준다.
클래스 의 내용을 한번 확인 해보자. 클래스 내용을 보면 가변 인자를 argument로 받아서 처리가 가능하도록 되어있다.
테스트 소스를 작성하기 전에 template 내용을 어떻게 사용해야하는지 알아야 한다.
아래의 샘플은 내가 처음 dateTemplate를 사용 하기 위해서 querydsl 공식 문서 및 여러 블로그를 찾아보았을때 나왔던 내용 이다. 하지만 아래의 방법으로 사용을 해도 정상적으로 데이터가 반환되지 않고 에러 메시지가 발생을 했었다.
// 사용 방법
Expressions.dateTemplate("반환할 타입 Class", "template 포맷", "인자")
// 사용 예시
Expressions.dateTemplate(LocalDate.class, "DATE_FORMAT({0}, '%Y-%m-%d')", targetDate)
에러의 내용을 살펴보면 반환할 타입으로 변환에 실패 했다고 나온다. 혹시 MariaDB 내부에서 DATE_FORMAT이 사용이 불가능한지를 테스트 해봤으나 정상적으로 날짜를 반환했다. 추가적으로 사용 방법에 대해서 내용을 추가적으로 확인 해본 결과 Dialect (방언) 설정 이다.
Spring boot를 실행하면서 연결되어있는 데이터 베이스에 맞게 설정이 된다고 알고 있다. (따로 설정을 건드릴 필요가 없다고...) 보통은 Hibernate 를 많이들 사용하고 있을것이다.
Hibernate는 특정 데이터베이스에 종속되지 않고 객체지향스럽게 사용할 수 있도록 추상화해준다. 때문에 특정 DB에 종속된 함수는 제공하지 않는다.😭😭
특정 데이터 베이스에서만 사용 가능한 함수를 호출할때는 Dialect를 확장해서 사용 해야한다. (소스는 샘플 소스를 작성 예정)
기존 Dialect를 확장해서 커스텀된 SQL을 작성하고 위의 방법에서 설명했던 template함수를 호출해본 결과 정상적으로 date type에 맞게 반환이 되는것을 확인 할수 있었다.
내가 찾아본 내용으로는 방언 설정시 명시적으로 버전을 설정해서 사용하는 경우 정상동작이 되지 않을수 있다. 또한 위에 썻던 내용 처럼 DB에 종속된 함수는 제공하지 않는다...
⚡샘플 소스
샘플 소스는 아직 작업 하지 않았지만 gitHub를 통해서 올릴 예정
⚡생각
querydsl을 사용 하면서 이런 저런 이슈들을 많이 만나고 있다...😂
가끔 이슈가 발생할때마다 한숨이 나오곤 하는데 성장하는 과정이라고 생각을 하고 있다. jpa 와 querydsl을 사용하면서 많이 느끼는 점은 속도 개선이다. 위의 방식도 사실 enttiy를 조회해서 반복을 통해서 java내에서 타입을 변환해서 사용하는 방법도 있다. 하지만 속도 개선을 위해서 위와 같은 방법을 찾고 사용하면서 버그를 찾고 수정하고 있다.
'Java' 카테고리의 다른 글
[Java] Wrapper Class 의 캐싱에 대한 내용 정리 (0) | 2023.04.16 |
---|---|
[JAVA] Stream에 대한 사용법 및 내용 정리 (0) | 2023.02.26 |
[JAVA] Tomcat error page 호출 관련 내용 정리 (0) | 2022.12.19 |
💀 디자인 패턴 및 리팩터링 개선 작업 내용 정리 (0) | 2022.11.27 |
Java 19 주요 내용 정리 (0) | 2022.09.20 |