본문 바로가기

Programming!

JPA QueryDsl 4.1.x 에서 groupBy, count(), orderBy 사용하기

이전 포스트

http://eclipse4j.tistory.com/213

 

위 포스트의 경우 3.x를 기준으로 작성을 했었는데.. 4.1.x의 경우는 Projections의 부분이 전체적으로 변경되었다.

 

이제 더이상 .list(Projections..) 을 지원하지 않는다

 

가볍게 예제를 들면.

사용자가의 검색어를 저장하는 search_keyword 테이블이 있고, 여기서 최근 많이 사용되는 keword와 특정아이디, 횟수를 구하고 싶은경우.

실제 매칭된 Entity는 SearchKeyword이지만, groupBy, count등을 해야 하므로 별도의 Dto를 만들어야 한다.(속성이 틀림)

여기서는 HotKeyword.java 로 보면 된다.

@Data
public class HotKeyword {


    @QueryProjection
    public HotKeyword(Long itemId, String keyword, Long quantity) {
        this.itemId = itemId;
        this.keyword = keyword;
        this.quantity = quantity;
    }

    @QueryProjection
    public HotKeyword(Long itemId, Long quantity) {
        this.itemId = itemId;
        this.results = quantity;
    }

    private Long regionId;

    private String keyword;

    private Long quantity;

}

위에서 @QueryProjection 선언된 생성자를 queryDsl에서 사용하게 된다.

..

QSearchKeyword qSearchKeyword = QSearchKeyword.searchKeyword;

from(qSearchKeyword)
.where(qSearchKeyword.createdAt.after(LocalDateTime.now().minusDays(days))

.groupBy(qSearchKeyword.itemId, qSearchKeyword.keyword)

.select(Projections.constructor(HotKeyword.class, qSearchKeyword.itemId, qSearchKeyword.keyword, qSearchKeyword.keyword.count()))

.fetch();

...

 

위와 같은 형태가 된다. 하지만 대게 해당 코드에서는 orderby를 count()에 걸어야 하는게 요구사항이라고 생각하니 아래처럼 path와 alias를 추가해서 걸어주자.

..

NumberPath<Long> aliasQuantity = Expressions.numberPath(Long.class, "quantity");

QSearchKeyword qSearchKeyword = QSearchKeyword.searchKeyword;

from(qSearchKeyword)
.where(qSearchKeyword.createdAt.after(LocalDateTime.now().minusDays(days))

.groupBy(qSearchKeyword.itemId, qSearchKeyword.keyword)

.select(Projections.constructor(HotKeyword.class, qSearchKeyword.itemId, qSearchKeyword.keyword, qSearchKeyword.keyword.count().as(aliasQuantity)))

.orderBy(aliasQuantity.desc())

.fetch();

...

 

 

대게 상위 10개 정도만 호출하니 limit도 걸자.

..

NumberPath<Long> aliasQuantity = Expressions.numberPath(Long.class, "quantity");

QSearchKeyword qSearchKeyword = QSearchKeyword.searchKeyword;

from(qSearchKeyword)
.where(qSearchKeyword.createdAt.after(LocalDateTime.now().minusDays(days))

.groupBy(qSearchKeyword.itemId, qSearchKeyword.keyword)

.select(Projections.constructor(HotKeyword.class, qSearchKeyword.itemId, qSearchKeyword.keyword, qSearchKeyword.keyword.count().as(aliasQuantity)))

.orderBy(aliasQuantity.desc())

.fetch().

.stream().limit(rows).collect(Collectors.toList());

 

위 코드는 대게 xxRepositoryCustom인터페이스를 구현한 클래스에서 작성이 되는 데, 코드를 보면 딱히 특정 테이블에 매칭된 Repository에 만들필요는 없다.

찾기 쉬운 곳에 놔두면 될 듯 하다.(비즈니스 코드내에 넣든, entity매핑 repository에 넣든..)

 

 

 

http://www.querydsl.com/static/querydsl/4.1.4/reference/html_single/