์๋ ,
QueryDSL์์ 'GROUP_CONCAT'์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ ์์ ๋ด๊ธฐ ์ํด ๊ณ ๊ตฐ๋ถํฌํ๊ณ ์์ต๋๋ค.
final QDataSourceSmallEliminate eliminate = QDataSourceSmallEliminate.dataSourceSmallEliminate;
final QLattitudeVisitor lattitude = LattitudeVisitorServiceImpl.$;
// Expressions.stringOperation(SQLOps.GROUP_CONCAT, lattitude.tagName)
return QuerydslUtils.newQuery(entityManager).select(Projections.constructor(EliminateLattitude.class,
eliminate.id,
JPAExpressions.selectDistinct( SQLExpressions.groupConcat(lattitude.tagName)).from(lattitude).where(lattitude.urlCrc.eq(eliminate.urlCrc))))
.from(eliminate)
.fetch();
์์ธ:
org.springframework.dao.InvalidDataAccessApiUsageException: No pattern found for GROUP_CONCAT; nested exception is java.lang.IllegalArgumentException: No pattern found for GROUP_CONCAT
...
Caused by: java.lang.IllegalArgumentException: No pattern found for GROUP_CONCAT
at com.querydsl.core.support.SerializerBase.visitOperation(SerializerBase.java:280)
at com.querydsl.jpa.JPQLSerializer.visitOperation(JPQLSerializer.java:437)
at com.querydsl.core.support.SerializerBase.visit(SerializerBase.java:231)
at com.querydsl.core.support.SerializerBase.visit(SerializerBase.java:31)
at com.querydsl.core.types.OperationImpl.accept(OperationImpl.java:83)
at com.querydsl.core.support.SerializerBase.handle(SerializerBase.java:92)
at com.querydsl.jpa.JPQLSerializer.serialize(JPQLSerializer.java:203)
at com.querydsl.jpa.JPQLSerializer.visit(JPQLSerializer.java:358)
at com.querydsl.jpa.JPQLSerializer.visit(JPQLSerializer.java:39)
at com.querydsl.core.types.SubQueryExpressionImpl.accept(SubQueryExpressionImpl.java:57)
at com.querydsl.core.support.FetchableSubQueryBase.accept(FetchableSubQueryBase.java:150)
at com.querydsl.core.support.SerializerBase.handle(SerializerBase.java:92)
at com.querydsl.core.support.SerializerBase.handle(SerializerBase.java:119)
at com.querydsl.core.support.SerializerBase.visit(SerializerBase.java:225)
at com.querydsl.core.support.SerializerBase.visit(SerializerBase.java:31)
at com.querydsl.core.types.ConstructorExpression.accept(ConstructorExpression.java:112)
at com.querydsl.core.support.SerializerBase.handle(SerializerBase.java:92)
at com.querydsl.jpa.JPQLSerializer.serialize(JPQLSerializer.java:203)
at com.querydsl.jpa.JPAQueryBase.serialize(JPAQueryBase.java:60)
at com.querydsl.jpa.JPAQueryBase.serialize(JPAQueryBase.java:50)
at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:98)
at com.querydsl.jpa.impl.AbstractJPAQuery.createQuery(AbstractJPAQuery.java:94)
at com.querydsl.jpa.impl.AbstractJPAQuery.fetch(AbstractJPAQuery.java:201)
at com.moraydata.general.secondary.repository.impl.DataSourceSmallEliminateRepositoryImpl.findObject(DataSourceSmallEliminateRepositoryImpl.java:98)
at com.moraydata.general.secondary.repository.impl.DataSourceSmallEliminateRepositoryImpl$$FastClassBySpringCGLIB$$b42d875d.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
QueryDSL 4.2.1 ๋ฐ JDK1.8 ๋ฐ Spring Boot2.0 ๋ฐ MySQL 5.7.
์ต์ ์ฐธ์กฐ ๋ฌธ์๋ฅผ ์ฝ์์ง๋ง ์ฌ์ ํ ๋ต์ ์ฐพ์ ์ ์์ต๋๋ค. ์๋ํ๋ ค๋ฉด ์ด๋ป๊ฒํด์ผํฉ๋๊น?
๋์์ฃผ์ธ์.
๋ฏธ๋ฆฌ ๊ฐ์ฌ๋๋ฆฝ๋๋ค.
์๋
ํ์ธ์.
JPAExpressions์ SQLExpressions๋ฅผ ํญ์ ํผํฉ ํ ์๋ ์์ต๋๋ค.
JPAExpressions์ SQLExpressions๋ฅผ ํญ์ ํผํฉ ํ ์๋ ์์ต๋๋ค.
๋ค, ๋น์ ๋ง์ด ๋ง์์. ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ ๋จ์๊ฐ ์์ต๋๋ค. ์ ์ฉํ ๊ฒ์ ์๋ํด๋ณด์ธ์.
๊ทธ๋ ๋ค๋ฉด JPAExpressions๋ฅผ ์ฌ์ฉํ ๋ GROUP_CONCAT์ด ํ์ํ ๊ฒฝ์ฐ ์ด๋ป๊ฒ ์ฒ๋ฆฌ ํ ์ โโ์์ต๋๊น?
์๋ ํ์ธ์.
์คํ๋ง ๋ถํธ ๋ฐ์ดํฐ jpa ๋ฐ querydsl-jpa
๊ฒฝ์ฐ ๋ค์ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅผ ์ ์์ต๋๋ค.
// org.hibernate.dialect.MySQL5Dialect
public class CustomMysqlDialect extends MySQL5Dialect {
public CustomMysqlDialect() {
super();
// register custom/inner function here
this.registerFunction("group_concat", new SQLFunctionTemplate(StandardBasicTypes.STRING, "group_concat(?1)"));
}
}
<strong i="15">@Configuration</strong>
public class JpaConfiguration {
<strong i="16">@Bean</strong>
public JpaVendorAdapter jpaVendorAdapter() {
AbstractJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
adapter.setShowSql(true);
adapter.setDatabase(Database.MYSQL);
// package to CustomMysqlDialect
adapter.setDatabasePlatform("com.xxx.xxx.config.CustomMysqlDialect");
adapter.setGenerateDdl(false);
return adapter;
}
}
// before do this , autowird JPAQueryFactory at first
QReportDoctorTag qReportDoctorTag = QReportDoctorTag.reportDoctorTag;
SimpleTemplate<String> simpleTemplate = Expressions.simpleTemplate(String.class, "group_concat({0})", qReportDoctorTag.tag);
JPAQuery<Tuple> tupleJPAQuery = queryFactory.select(qReportDoctorTag.reportId, simpleTemplate)
.from(qReportDoctorTag)
.groupBy(qReportDoctorTag.reportId);
List<Tuple> fetch = tupleJPAQuery.fetch();
SQL์ ๊ฒฝ์ฐ SQLExpressions.groupConcat
. JPA์ ๊ฒฝ์ฐ GROUP_CONCAT
๋ JPQL์ ๋ํด ์ ์ ๋ ํจ์๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ง์๋์ง ์์ต๋๋ค. ์ด๋ค ๊ฒฝ์ฐ์๋ ๊ธฐ๋ฅ์ ์๋์ผ๋ก ๋ฑ๋ก ํ ์ ์์ง๋ง ORM ๊ณต๊ธ ์
์ฒด ์ค ์ด๋ ๊ฒ๋ ๊ธฐ๋ณธ์ ์ผ๋ก์ด๋ฅผ ์ ๊ณตํ์ง ์์ต๋๋ค (์ ์ค๋ช
์ ์ ์ฐธ์กฐ).
# 2020๊ณผ ์ค๋ณต๋ฉ๋๋ค.
@ giraffe-tree ์๋ ํ์ธ์. "GROUP_CONCAT ({0} ORDER BY {1})"๋ฅผ ์ฌ์ฉํ๊ณ ์ถ์ต๋๋ค. ํจ์ ๋ฑ๋ก์ ์ด๋ป๊ฒํ๋์? ๋ถ๋.
JPA์์๋ ์ง์๋์ง ์์ต๋๋ค. ๋จผ์ ORM ๊ณต๊ธ ์ ์ฒด์์ด๋ฅผ ๊ตฌํํ๋๋ก ์์ฒญํด์ผํฉ๋๋ค (์ : Hibernate).
blaze-persistence-querydsl
ํ์ฅ์ ์ฌ์ฉํ์ฌ ๊ณต๋ฐฑ์ ๋ฉ์ธ ์ ์์ต๋๋ค. https://persistence.blazebit.com/documentation/1.5/core/manual/en_US/index.html#querydsl -integration
๋ค์๊ณผ ๊ฐ์ ๋ฐฉ๋ฒ์ด ์์ต๋๋ค.
JPQLNextExpressions.groupConcat(Expression<?> expression, String separator, OrderSpecifier<?>... orderSpecifiers)
JPQLNextExpressions.groupConcat(Expression<?> expression, Expression<String> separator, OrderSpecifier<?>... orderSpecifiers)
JPQLNextExpressions.groupConcat(boolean distinct, Expression<?> expression, String separator, OrderSpecifier<?>... orderSpecifiers)
JPQLNextExpressions.groupConcat(boolean distinct, Expression<?> expression, Expression<String> separator, OrderSpecifier<?>... orderSpecifiers)
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
์๋ ํ์ธ์.
์คํ๋ง ๋ถํธ ๋ฐ์ดํฐ jpa ๋ฐ
querydsl-jpa
๊ฒฝ์ฐ ๋ค์ ๋จ๊ณ๋ฅผ ๋ฐ๋ฅผ ์ ์์ต๋๋ค.