QueryDSL
프로젝트 이관
Q-Types multi thread loading 시 dead lock
// 미리 초기화를 호출하는게 좋다. packageToLoad 를 변경해준다.
ClassPathUtils.scanPackage(Thread.currentThread().getContextClassLoader(), packageToLoad);
join 성능 향상
from(parent).innerJoin(parent.child).fetch()
....
JPA QueryDSL Cross Join 발생
Parent - Child
가 1:1 관계일 때 다음과 같이 쿼리했더니 inner join과 cross join이 함께 발생했다.
QParent parent = QParent.parent;
QChild child = parent.child;
from(parent).innerJoin(parent.child).fetch()
.where(parent.something.gt(parent.child.somthing))....;
다음처럼
innerJoin
에 PATH를 지정했더니 cross join이 사라졌다.
QParent parent = QParent.parent;
QChild child = QChild.child; // 여기 달라짐
from(parent).innerJoin(parent.child, child).fetch() // as 처리가 필요함.
.where(parent.something.gt(child.somthing))....;
JPA Subquery & JPAExpressions
Native 조건 condition
Expressions의
xxxTemplate
를 통해서 native 쿼리 조건을 만들어 낼 수 있다.
JPA 사용시에는 해당 함수가
Hibernate dialect에 함수(
registerFunction
)로 등록돼 있어야 한다.
// MySQL의 TIMESTAMPDIFF를 Expression으로 만들기
Expressions.numberTemplate(Long.class,
"TIMESTAMPDIFF(HOUR, {0}, {1})",
QSomething.dateField,
QOtherThing.anotherDateField);
// 이것을 메소드로 빼면 다음과 같은 형태가 된다.
public static NumberExpression<Long> hourDiff(
Expression<? extends Date> left,
Expression<? extends Date> right) {
return Expressions.numberTemplate(Long.class, "TIMESTAMPDIFF(HOUR, {0}, {1})", left, right);
}
상수가 들어가는 표현식
// 0.12 - w.totalCost 를 나타내고자 한다.
Expressions.operation(Float.class, Ops.SUB,
Expressions.constant(0.12f), w.totalCost)
// or
NumberOperation.create(Float.class, Ops.SUB,
Expressions.constant(0.12f), w.totalCost)
복잡한 쿼리
복잡한 쿼리는
BooleanBuilder
를 사용한다.
public List<Customer> getCustomer(String... names){
QCustomer customer = QCustomer.customer;
HibernateQuery qry = new HibernateQuery(session).from(customer);
BooleanBuilder builder = new BoolenBuilder();
for (String name : names){
builder.or(customer.name.eq(name));
}
qry.where(builder); // customer.name eq name1 OR customer.name eq name2 OR ...
return qry.list(customer);
}
Case/When
-
CaseBuilder
사용.
CaseBuilder
사용시 when
과, otherwise
는 ?
파라미터로 안먹고 무조건 상수로만 먹는듯 보임.
따라서, when
과 otherwise
가 DB 입장에서 봤을 때 동일한 타입이 되는 상수로 맞춰줘야 한다.
// registerDate 가 DATE 컬럼 일때
// newRegisterDate 는 LocalDateTime.class
Expression<LocalDateTime> modifyDateTime = new CaseBuilder()
.when(qUser.registerDate.eq(expectedRegisterDate))
.then(qUser.registerDate) // DB 입장에서 DATE 컬럼
.otherwise(
// DB 입장에서 DATE 인 'TO_DATE' 함수를 사용해서 변경해줌. 상수값만
// 들어가기 때문에 어쩔 수 없이 문자로 모든 것을 넣어줌
Expressions.dateTimeTemplate(LocalDateTime.class, "to_date({0}, {1})",
newDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")),
Expressions.constant("yyyy-MM-dd HH:mm:ss"))
);
@Embeddable의 필드 소스 생성
-
-
Java 7에서
SimpleSerializerConfig.getConfig
에서
NullPointerException
발생하는 경우가 있는데 이는 QueryDSL과 아무 상관 없는 코드 중에 의존성에 들어가지 않는 Annotation을 넣은게 있었기 때문이었다(Java 8에서는 올바른 컴파일 오류 지점이 보였음).
Caused by: java.lang.NullPointerException
at com.mysema.query.codegen.SimpleSerializerConfig.getConfig(SimpleSerializerConfig.java:29)
at com.mysema.query.apt.DefaultConfiguration.<init>(DefaultConfiguration.java:137)
at com.mysema.query.apt.jpa.JPAConfiguration.<init>(JPAConfiguration.java:54)
...
참고