에브리타임 클론 코딩 프로젝트 정리 - JPA

yshjft·2022년 7월 11일
0

Querydsl and or 괄호 묶기

간단하다. BooleanBuilder를 사용하면 된다. and()가 새로운 괄호의 시작이다. and()를 사용하면 괄호로 묶인다고 생각하자.

참고 자료

Query dsl & pageable sort

프로젝트에서 페이징 정보(page, size, sort)를 Pageable(실제로 받은 것은 PageRequest로 예상된다)로 받을 수 있도록 하였다. 따라서 query-dsl과 pageable을 이용하여 아래와 같이 쿼리에 정렬을 적용해보았다.

Pageable 객체에 정렬조건 null 여부를 체크한 후 정렬 조건이 존재한다면 반복문을 통해 정렬 조건을 가져오고 이를 OrderSpecifier에 담아 반하도록 하였다. 현재 코드에서는 모든 정렬을 오름차순으로 설정하였지만 Pageable에서 얻어낸 정렬 조건에서 정렬 순서를 가져와 적용할 수 있다.

Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC;

여러 조건으로 정렬하기

현재 코드에서는 오로지 하나의 정렬 조건만을 고려하고 있다. 다수의 정렬 조건이 적용된다면 아래와 같이 다른 방법을 적용해야 한다.

ex) /api/tutorials?page=0&size=3&sort=published,desc&sort=title,asc

private List<OrderSpecifier> getAllOrderSpecifiers(Pageable pageable) {

    List<OrderSpecifier> ORDERS = new ArrayList<>();

    if (!isEmpty(pageable.getSort())) {
        for (Sort.Order order : pageable.getSort()) {
            Order direction = order.getDirection().isAscending() ? Order.ASC : Order.DESC;
            switch (order.getProperty()) {
                case "id":
                    OrderSpecifier<?> orderId = QueryDslUtil.getSortedColumn(direction, QRoom.room, "id");
                    ORDERS.add(orderId);
                    break;
                case "user":
                    OrderSpecifier<?> orderUser = QueryDslUtil.getSortedColumn(direction, QUser.user, "name");
                    ORDERS.add(orderUser);
                    break;
                case "category":
                    OrderSpecifier<?> orderCategory = QueryDslUtil.getSortedColumn(direction, QRoom.room, "category");
                    ORDERS.add(orderCategory);
                    break;
                default:
                    break;
            }
        }
    }

    return ORDERS;
}

...

// 정렬 조건 적용
orderBy(ORDERS.stream().toArray(OrderSpecifier[]::new))

부가적인 내용 1

class PageRequest extends AbstractPageRequest { … }

abstract class AbstractPageRequest implements Pageable, Serializable { … }

부가적인 내용 2

orderBy에 null 반환시 에러가 발생한다. null을 반화하지마라.

부가적인 내용 3

/api/tutorials?page=0&size=3&sort=published 와 같이 정렬 방향에 대한 정보를 입력하지 않은 경우 오름차순(ASC)이 적용된다.

참고 자료

query-dsl contains, like

  • contains
    • %검색어%
    • 포함 여부
  • like
    • 검색어
    • 완전 일치 여부

참고 자료

Querydsl Invalid path

org.hibernate.hql.internal.ast.QuerySyntaxException: Invalid path: ~~~ 와 같은 에러를 query-dsl을 사용하다가 만나게 되었다. 해당 문제에 대한 답변을 이 사이트에서 찾을 수 있었다. 일단 Invalid Path라는 것은 두 엔티티간의 관계가 무엇인지 모르겠다는 것을 의미한다고 한다. 이를 해결하기 위해서는 Querydsl에게 두 엔티티간의 관계를 알려주어야 한다고 한다. 즉, join 또는 fetch join할 경우 조인 대상만 명시하지말고 별칭으로 사용할 Q타입까지 명시해주면 해당 문제를 해결할 수 있다.

join(조인 대상, 별칭으로 사용할 Q타입)

DTYPE 엔티티 필드

만약 Dtype 값을 엔티티에서 필드로 직접 사용할 필요가 있다면 @Column(insertable = false, updatable = false)을 이용하여 읽기 전용으로 사용하면 된다.

컬렉션 페치 조인(ToMany fetch join)과 페이징

컬렉션 페치 조인은 페이징이 불가능하다. 페이징을 시도한다면 모든 데이터를 메모리에 로딩을 하고 메모리에서 페이징을 하게된다. (굉장히 많은 데이터를 한번에 메모리에 올린다면…?)

QueryDsl과 Bulk Update

처음에 위의 코드를 작성할 때 아래와 같은 내용들을 제대로 알지 못하고 작성하였다.

  • bulk update로 인한 flush는 JPQL과 관련있는 엔티티에만 해당해서 발생한다. 예를 들어 Enrollment에 대해 bulk update가 일어났다면 Enrollment에 한해서만 flush가 발생하게 되는 것이다.
  • @Modifying 은 @Query로 벌크성 쿼리 보낼 때만 사용된다. QuerDsl에서 사용할 수 없는 어노테이션이다. QuerDsl에서 @Modifying과 관련된 효과를(auto flush, auto clear) 얻고 싶다면 직접 em.flush()와 em.clear를 해주어야 한다.

처음에 위의 코드를 작성하였을 때 bulk delete 후 flush와 clear 처리를 하지 않았다. 이러한 이유 때문인지는 모르겠지만 bulk delete는 모두 동작하는데 timetableRepository.delete(timetable)는 동작하지 않는 기현상이 발생하였다. 하지만 bulk delete 후 flush와 clear 처리를 한 후 timetableRepository.delete(timetable) 제대로 동작하게 되었다. 문제는 이유를 모르겠다.

jpql flush에 대하여

profile
꾸준히 나아가자 🐢

0개의 댓글