실전! Querydsl
만료된 메서드 fetchResult(), Blaze-persistence 세팅 관련 글 공유드립니다.
QueryDSL 내부 메소드 중fetchResult() 나 fetchCount()는 만료된 메소드에 대해서는 QueryDSL에서 Blaze-persistence Integration 라이브러리 사용을 권장하는데요,Blaze-persistence도 QueryDSL 처럼 쿼리 빌더 API 로서 개발자에게 유지보수하기 좋은 객체를 제공해주고 있습니다.게다가 최신 업데이트 날짜가 글 작성일 기준(2023.06.21) 일주일 이전이라 여전히 유지보수되고 있어서 최신 스프링버전과 호환성도 어느정도 보장되었다고 볼 수 있습니다.개인적으로 SpringBoot 3.1.0 기준으로 다음과 같이 세팅하니 정상적으로 동작하는 걸 확인했는데요, 혹시 저처럼 deprecated 메소드를 쓰는 것이 신경쓰이시는 분들을 위해 공유드립니다.build.gradledependencies {
//Blaze-Persistence
implementation 'com.blazebit:blaze-persistence-integration-querydsl-expressions-jakarta:1.6.9'
implementation 'com.blazebit:blaze-persistence-integration-hibernate-6.2:1.6.9'
implementation 'com.blazebit:blaze-persistence-core-impl-jakarta:1.6.9'
} BlazePersistenceConfiguration.java@Configuration
public class BlazePersistenceConfiguration {
@PersistenceUnit
private EntityManagerFactory entityManagerFactory;
@Bean
@Scope(ConfigurableBeanFactory.SCOPE_SINGLETON)
@Lazy(false)
public CriteriaBuilderFactory createCriteriaBuilderFactory() {
CriteriaBuilderConfiguration config = Criteria.getDefault();
// do some configuration
return config.createCriteriaBuilderFactory(entityManagerFactory);
}
}QuerydslBasicTest.java.....
JPAQueryFactory queryFactory;
@Autowired
CriteriaBuilderFactory cbf;
BlazeJPAQueryFactory blazeQueryFactory;
@BeforeEach
public void testEntity(){
queryFactory = new JPAQueryFactory(em); // 이건 동시성 문제를 고민하지 않아도 됨, 해결됨
blazeQueryFactory = new BlazeJPAQueryFactory(em, cbf);
..... 적용 결과기존 QueryDSL 세팅한 것에 추가로 세팅하시면, 만료된 메소드에 대해 Blaze-persistence 객체로 대체되는데요, 기존 querydsl 클래스를 상속 받는 형태여서 QueryDSL이 제공하는 메소드를 그대로 쓸 수도 있습니다.fetchResults는 fetchPage로 바꿔서 사용할 것을 권장하고 있다는 점 참고하시면 될 것 같습니다.추가로 내부로직이라든지 설명이 더 필요하시다면 Blaze-persistence 릴리즈 노트와 Blaze Persistence Document를 참고하시면 좋을 것 같습니다.이 글에 대해 지적 및 피드백 해주시면 정말 감사하겠습니다.감사합니다. 여담 및 고민 :개인적으로 이 라이브러리의 내부로직을 뜯어보면서 분석하고 검증할 수 있는 역량은 부족한지라 분석 및 검증하는 방법에 대해서 팁이라든지, 아니면 blaze-persistence 사용할 시 주의해야할 점이라든지 조언해주실 수 있으시면 정말 감사드립니다. 강의를 듣던 중에 서브쿼리가 발생하는 부분에서는 정상동작하지 않는 것을 발견했습니다.@Test
public void findUserDto(){
QMember memberSub = new QMember("memberSub");
List<UserDto> memberDtoList = queryFactory //이건 blazeQueryFactory가 정상 동작하지 않음
.select(Projections.fields(UserDto.class, //생성자 필드 순서에 맞게 변수를 만들어야 한다.
member.username.as("name"),
// member.age 대신 서브쿼리로 다 최대 나이로 찍고 싶어
ExpressionUtils.as(
JPAExpressions
.select(memberSub.age.max())
.from(memberSub), "age")
))
.from(member)
.fetch();
for (UserDto userDto : memberDtoList) {
System.out.println("userDto = " + userDto);
}
}
QueryDSL 쿼리 /* select
member1.username as name,
(select
max(memberSub.age)
from
Member memberSub) as age
from
Member member1 */ select
m1_0.username,
(select
max(m2_0.age)
from
member m2_0)
from
member m1_0 blaze-persistence 쿼리 /* SELECT
member1.username AS name,
member1.age AS generatedSubquery_1
FROM
Member member1 */ select
m1_0.username,
m1_0.age
from
member m1_0 blaze-persistence generatedSubquery라 하여, 서브쿼리를 하나의 alias로 처리를 해버렸는데, 후행으로 이 generatedSubquery 에 대한 정의가 따라오질 않습니다...왜 이런 차이가 나오는지는 모르겠지만 blaze-persistence 활용할 때는 유의해야할 것 같습니다.