관리 메뉴

취미개발 블로그와 마음수양

QueryDSL - group_concat 과 subQuery등 잡다쿼리(?)를 할 때는 QueryDSL sql 을 검토해보자 본문

FrameWork_ETC/JPA_Hibernate

QueryDSL - group_concat 과 subQuery등 잡다쿼리(?)를 할 때는 QueryDSL sql 을 검토해보자

아라한사 2019. 1. 8. 23:29

개인프로젝트를 하면서 혼자서 요구사항이 생겼는데..

서브쿼리에 group_concat을 사용하는 것이었다.


아 서브쿼리에 group_concat을 사용하는 경우.. 뭐 이런 경우가 있을 수 있겠다.


어떤 게시글 내용을 조회하는데 엮인 태그를 조회하는 경우?랄까?

하나의 내용  ( + 태그 row 여러 줄 내용을 한줄로 => #삽질 #야근 ) 

이런저런 경우가 있을텐데..


뭐.. 쿼리 직접 짜서 JDBC template돌리면 금방할 수도 있겠지만.. 

개인프로젝트가 queryDSL으로 많이 되어있기도 하고, 그리고 페이지별로 컨텐츠 수를 일별로 수집한 데이터 갯수에 따라 다르게 하는
동적 일별 페이징기능을 queryDSL에 적용해둔 지라..

해당 기능을 그대로 살리면서 저런 queryDSL 기능을 적용하고 싶었다. (자식자랑하는 심정인가 음;; )


잠깐 찾아보니 groupBy가 있고 SQLExpressions.groupConcat() 란 기능이 있어서 써봤는데 

암만 해도 No pattern found for GROUP_CONCAT; 에러로그가 나왔다.. 


아..이슈를 보니.. 

https://github.com/querydsl/querydsl/issues/2377


내가 사용하는 것은 JPAQuery 였고 저기 위의 SQLExpressions 의 기능은 querydsl SQL query라는 기능이었다.

저걸 사용하려면 보통의 JPA Query를 사용하는 것이 아닌 다른 방식으로 사용을 해야했는데 우선..


query dsl - sql 부분을 참고하여 

http://www.querydsl.com/static/querydsl/latest/reference/html/ch02s03.html#d0e1067


compile("com.querydsl:querydsl-sql:${versions.querydsl}")
compile("com.querydsl:querydsl-sql-spring:${versions.querydsl}")


다음의 빌드를 추가해주고 저기 레퍼런스에 나온대로 다음의 빈들을 설정해준다. 

@Bean
public com.querydsl.sql.Configuration querydslConfiguration() {
SQLTemplates templates = MySQLTemplates.builder().build(); //change to your Templates
com.querydsl.sql.Configuration configuration = new com.querydsl.sql.Configuration(templates);
SpringExceptionTranslator springExceptionTranslator = new SpringExceptionTranslator();
configuration.setExceptionTranslator(springExceptionTranslator);
return configuration;
}

@Bean
public SQLQueryFactory queryFactory() {
Provider<Connection> provider = new SpringConnectionProvider(dataSource());
SQLQueryFactory sqlQueryFactory = new SQLQueryFactory(querydslConfiguration(), provider);
return sqlQueryFactory;
}

음 그리고 쿼리 사용부분에서 sqlQueryFactory 를 autowired 해온다. query 는 여기 factory에서 가져와 사용하면 된다.

@Autowired
SQLQueryFactory sqlQueryFactory;

이렇게 해준다음에 저기 위의 SqlExpression 등을 사용해주면 되는데.. 

문제가 약간 생긴것이 .. 내가 아직 좀 들봐서 그런 걸 수도 있는데

JPA query 의 테이블명과 조인컬럼을 그대로 읽어오질 못하였다. 

그래서 queryDSL의 .innerjoin(필드명) 하려는데 생성된 쿼리문이 그대로 필드명 대로 나와버린 것이다; 두둥;; 


그래서 SQL Query 에서 사용할  QClass를 다음과 같은 형태로 직접 정의하였다. 
(난 당장 급한 개인요구사항 해결이 급해서 여기까지만;; 이 글을 적는 이유..도 사실.. 나머지를 완성해줘 지구인들! 음? )


class QDailyCondition extends RelationalPathBase<QDailyCondition>{
public QDailyCondition(String path) {
super(QDailyStockConditionSearch.class, PathMetadataFactory.forVariable(path), "", "tablename");
}
public final DatePath<Date> day = createDate("day", Date.class);
public final NumberPath<Long> j = createNumber("j_id", Long.class);
}

이렇게 하고서 사용하면 다음과 같은 서브쿼리 형태도 동작하게 되고.. 서브쿼리 자체로도 그대로 동작시키면 동작한다. 

직접추가한 QClass 와 쿼리DSL이 자동생성한 QClass와 혼용가능하였다.


SQLQuery<String> subQuery = query.select(
SQLExpressions.groupConcat(qt.name)).from(qtj)
.innerJoin(qt)
.on(qt.id.eq(qtj.t))
.groupBy(qtj.j).where(qs.id.eq(qtj.j));

query.select(qdc.day, qs.name, subQuery)
.from(qdc)
.innerJoin(qs)
.on(qs.id.eq(qdc.j));

query.fetch()

뭐 이런 느낌..음..


별로 글 안 보여서 삽질한 경험 공유..  재밌긴허다! ㅎㅎ 

음 QClass직접 정의할 때는 귀찮았는데 재사용성이 있으니..그래도 좀 편하지 않을까하는 생각도 들긴하는..


권남님 블로그에서도 해당 이야기를 찾아볼 수 있었다

http://kwonnam.pe.kr/wiki/java/querydsl/nativesql


서로의 야근을 줄여주기 위한 개발자의 블로깅.

'FrameWork_ETC > JPA_Hibernate' 카테고리의 다른 글

intellij QueryDSL 설정  (1) 2017.09.21
hibernate.cfg.xml  (0) 2014.10.24