[Spring] Spring Data JPA Native Query 작성 시 필요한 것들

[Spring] Spring Data JPA Native Query 작성 시 필요한 것들

Spring Data JPA에서 Native Query를 작성하는 것은 크게 어렵지 않습니다.

public interface PostRepository extends JpaRepository { @Query(value = "SELECT * FROM post", nativeQuery = true) List findAllPost(); }

위처럼 @Query 어노테이션을 사용하여 쿼리를 입력하고, nativeQuery 옵션을 true로 주시면 됩니다.

하지만 해당 쿼리는 findAll 같은 기본 JPA가 자동으로 생성해주는 쿼리를 사용하면 되기 때문에,

테이블에서 특정 컬럼만 가져오거나, 여러 테이블을 조인하거나 할 때, Native Query를 사용하게 될 겁니다.

public interface PostRepository extends JpaRepository { @Query(value = "SELECT p.id, p.title, p.content, p.views, u.nickname, count(r.post_id) as likes " + "FROM post as p " + "LEFT JOIN user as u " + "ON p.user_id = u.id " + "LEFT JOIN recommendation as r " + "ON p.id = r.post_id " + "GROUP BY p.id", nativeQuery = true) List findAllPost(); }

이런 쿼리가 필요하다고 할 때, SELECT된 데이터는 총 6개입니다.

u.nickname 이나 count(r.post_id)는 Post 엔티티에 존재하지 않기 때문에, 매핑이 되지 않는데요.

이럴 때 Interface를 만들어 매핑 시켜 줄 수 있습니다.

public interface PostInterface { Long getId(); String getTitle(); String getContent(); int getViews(); String getNickname(); int getLikes(); }

그런 다음 Service 단에서 Dto로 변환 후 Controller에 반환해 주면 됩니다.

@Transactional(readOnly = true) public List readAllPost() { return postRepository.findAllPost() .stream() .map(PostDto::new) .collect(Collectors.toList());

하지만 여기에 그치지 않고 pagination 작업이 필요한 경우가 있을 텐데요.

@Transactional(readOnly = true) public List readAllPost(int page, int size) { PageRequest pageRequest = PageRequest.of(page, size); return postRepository.findAllPost(pageRequest) .stream() .map(PostDto::new) .collect(Collectors.toList()); }

List로 반환을 하게 되면 추가적인 작업 없이 PageRequest 객체만 파라미터로 받아오게끔 해주면 됩니다.

public interface PostRepository extends JpaRepository { @Query(value = "SELECT p.id, p.title, p.content, p.views, u.nickname, count(r.post_id) as likes " + "FROM post as p " + "LEFT JOIN user as u " + "ON p.user_id = u.id " + "LEFT JOIN recommendation as r " + "ON p.id = r.post_id " + "GROUP BY p.id", nativeQuery = true) List findAllPost(PageRequest pageRequest); }

데이터의 총개수나 전체 페이지 수 등을 알기 위해선 Page로 반환을 해야 합니다.

이때 반환형만 Page로 바꿔주게 되면 에러가 발생하게 됩니다.

org.h2.jdbc.JdbcSQLSyntaxErrorException: Column "P" not found; SQL statement:

select count(p) FROM post as p LEFT JOIN user as u ON p.user_id = u.id LEFT JOIN recommendation as r ON p.id = r.post_id GROUP BY p.id [42122-200]

저는 해당 에러가 떴었는데, 찾아보니 Native Query를 사용할 경우 개수를 세는 countQuery를 따로 적어줘야 합니다.

public interface PostRepository extends JpaRepository { @Query(value = "SELECT p.id, p.title, p.content, p.views, u.nickname, count(r.post_id) as likes " + "FROM post as p " + "LEFT JOIN user as u " + "ON p.user_id = u.id " + "LEFT JOIN recommendation as r " + "ON p.id = r.post_id " + "GROUP BY p.id", countQuery = "SELECT * FROM post", nativeQuery = true) Page findAllPost(PageRequest pageRequest); }

프로젝트에 Native Query를 적용시키다 겪은 시행착오에 대해 적어봤는데,

틀린 점이 있다면 언제든지 알려주시면 감사하겠습니다.

from http://hackids.tistory.com/129 by ccl(A) rewrite - 2021-12-29 03:01:34