필요한 컬럼만 가져오기 (생각)
엔티티 전부를들고와서 PC에 띄우는 형식으로 돼있다.
필요한 컬럼만들고 오는걸로 변환하자.
리팩토링 전 코드
베스트셀러 구하는 쿼리
@Query("SELECT b,a FROM BookHistory bh JOIN bh.book b join bh.book.author a GROUP BY b.id ORDER BY COUNT(bh.id) DESC")
List<Book> findBooksByHistory();
주간 베스트 셀러 구하는 쿼리
@Query("SELECT b,a FROM BookHistory bh JOIN bh.book b join bh.book.author a WHERE bh.createdAt >= :startOfWeek AND bh.createdAt <= :endOfWeek GROUP BY b.id ORDER BY COUNT(bh.id) DESC")
List<Book> findWeekBestSellers(@Param("startOfWeek") LocalDateTime startOfWeek, @Param("endOfWeek") LocalDateTime endOfWeek);
일별 베스트 셀러 구하는 쿼리
@Query("SELECT b FROM BookHistory bh JOIN bh.book b JOIN fetch bh.book.author a WHERE bh.createdAt >= :startOfDay AND bh.createdAt <= :endOfDay GROUP BY b.id ORDER BY COUNT(bh.id) DESC")
Page<Book> findTopDayBestSeller(@Param("startOfDay") LocalDateTime startOfDay,
@Param("endOfDay") LocalDateTime endOfDay,
Pageable pageable);
이어보기 구하는 쿼리
@Query("SELECT bh FROM BookHistory bh JOIN FETCH bh.book b JOIN FETCH bh.user u WHERE u.id = :userId")
List<BookHistory> findBookHistoryByUserId(@Param("userId") Integer userId);
필요한 컬럼만 가져오기 (적용)
1.해결방법 (JPA 문법 오류)
필요한 컬럼만 들고 오려고하니 JPA가 매핑되는 엔티티를 찾지 못해서 오류가 났다
2.해결방법(DTO 프로젝션 오류)
DTO 프로젝션 방식을 해결하려고 했는데 형태가 클레스 안에 클레스가 있다보니까
JPA가 내부 클레스에 DTO 경로 인식을 못해 오류가 났다.
3.해결방법(인터페이스 프로젝션 완료)
인터페이스 기반 프로젝션은 메서드명으로 컬럼 이름이랑 매핑 하기 때문에
JPA가 알아서 매핑해줘서 해결했다.
리팩토링 후 코드
베스트셀러 구하는 쿼리
@Query(value = """
SELECT
b.id AS id,
b.path AS bookImagePath,
b.title AS bookTitle,
a.name AS author,
COUNT(bh.id) AS readCount
FROM book_history_tb bh
JOIN book_tb b ON bh.book_id = b.id
JOIN author_tb a ON b.author_id = a.id
GROUP BY b.id, b.path, b.title, a.name
ORDER BY readCount DESC
""", nativeQuery = true)
List<BestSellerProjection> findBestSellers();
주간 베스트 셀러 구하는 쿼리
@Query(value = """
SELECT
b.id AS id,
b.path AS bookImagePath,
b.title AS bookTitle,
a.name AS author,
COUNT(bh.id) AS readCount
FROM book_history_tb bh
JOIN book_tb b ON bh.book_id = b.id
JOIN author_tb a ON b.author_id = a.id
WHERE bh.created_at BETWEEN :startOfWeek AND :endOfWeek
GROUP BY b.id, b.path, b.title, a.name
ORDER BY readCount DESC
""", nativeQuery = true)
List<WeekBestSellerProjection> findWeekBestSellersNative(@Param("startOfWeek") LocalDateTime startOfWeek, @Param("endOfWeek") LocalDateTime endOfWeek);
일별 베스트 셀러 구하는 쿼리
@Query(value = """
SELECT
b.id AS id,
b.title AS bookTitle,
a.name AS author,
b.book_intro AS bookIntro,
b.path AS bookImagePath
FROM book_history_tb bh
JOIN book_tb b ON bh.book_id = b.id
JOIN author_tb a ON b.author_id = a.id
WHERE bh.created_at BETWEEN :startOfDay AND :endOfDay
GROUP BY b.id, b.title, a.name, b.book_intro, b.path
ORDER BY COUNT(bh.id) DESC
LIMIT 1
""", nativeQuery = true)
DayBestSellerProjection findDayBestSellerNative(@Param("startOfDay") LocalDateTime startOfDay,
@Param("endOfDay") LocalDateTime endOfDay);
이어보기 구하는 쿼리
@Query(value = """
SELECT
bh.user_id AS userId,
b.id AS bookId,
b.title AS bookTitle,
b.page_count AS pageCount,
bh.last_read_page AS lastReadPage,
b.path AS bookImagePath
FROM book_history_tb bh
JOIN book_tb b ON bh.book_id = b.id
WHERE bh.user_id = :userId
""", nativeQuery = true)
List<BookHistoryProjection> findContinueReadingBooks(@Param("userId") Integer userId);
Interface
베스트셀러
public interface BestSellerProjection { //"인터페이스 기반 Projection은 Native Query나 JPQL을 통해 조회 시,쿼리 결과가 getter 메서드 명과 자동 매핑된다."
Integer getId();
String getBookImagePath();
String getBookTitle();
String getAuthor();
Long getReadCount();
}
주간 베스트셀러
public interface WeekBestSellerProjection {
Integer getId();
String getBookImagePath();
String getBookTitle();
String getAuthor();
Long getReadCount();
}
일간 베스트셀러
public interface DayBestSellerProjection {
Integer getId();
String getBookTitle();
String getAuthor();
String getBookIntro();
String getBookImagePath();
}
이어보기
public interface BookHistoryProjection {
Integer getUserId();
Integer getBookId();
String getBookTitle();
Integer getPageCount();
Integer getLastReadPage();
String getBookImagePath();
}
Share article