JQPL 맵핑하기
- JPQL에서 DTO Mapping과 interface를 이용한 매핑 방법입니다.
- Interface 매핑시 주의 사항
as(별칭)을 사용하여 PostMapping클래스의 필드명과 맞추는 작업이 필요합니다. 별칭이 맞지 않다면 null을 반환합니다.
- DTO 매핑시 주의사항
데이터를 받을 생성자가 꼭 필요하고 정의해야 합니다.
필드명과 맞출 필요 x, 별칭 사용할 이유 x, but 생성자 파라미터의 데이터 타입을 엔티티의 타입과 반드시 맞춰 사용해야 합니다!.
//Repository
public interface PostRepository extends JpaRepository<Post, Long> {
//interface를 사용한 매핑 방법
@Query("select p.id as id, p.content as content, p.title as title, p.writer as writer, p.updatedAt as updatedAt, " +
"(select count(cp.comment.id) from CommentPostAssociation cp where cp.post.id = p.id) as commentCount " +
"from Post p join fetch Board b on b.id = p.board.id " +
"where b.url = :boardUrl " +
"order by p.id DESC")
Page<PostMapping> findPostByBoardUrlWithPagination(String boardUrl, Pageable pageable);
@Query("select new org.ruu.developerkorea.domain.board.model.dto.post.PostDTO(p.id, p.title, p.content, p.writer, p.updatedAt, " +
"(select count(cp) from CommentPostAssociation cp where cp.post.id = p.id) ) " +
"from Post p join fetch Board b on b.id = p.board.id " +
"where b.url = :boardUrl " +
"order by p.id DESC")
Page<PostDTO> findPostByBoardUrlWithPagination2(String boardUrl, Pageable pageable);
}
//PostDTO
@Builder
@Getter
@ToString
public class PostDTO {
private Long id;
private String title;
private String content;
private String writer;
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy.MM.dd")
private LocalDateTime updatedAt;
private Long commentCount;
public PostDTO(Long id, String title, String content, String writer, LocalDateTime updatedAt, Long commentCount) {
this.id = id;
this.title = title;
this.content = content;
this.writer = writer;
this.updatedAt = updatedAt;
this.commentCount = commentCount;
}
public PostDTO() {
}
}
//PostMapping
public interface PostMapping {
Long getId();
String getContent();
String getTitle();
String getWriter();
LocalDateTime getUpdatedAt();
long getCommentCount();
}
두가지 매핑 방식 사용하기
- Interface 방식은 Mapping 인터페이스가 존재하여 mapper용 파일이라는 것을 명확히 할 수 있습니다.
- 하지만, 한번 더 변환하거나 별칭을 맞춰야 하는 불편함이 존재합니다.
- 두 방식 모두
DTO 및 PostMapping의 필드 이름의 변경이 일어나더라도 타입이 같다면 코드가 정상 동작할 수 있습니다. 하지만 그 경우데이터가 NULL을 반환할 수 있기 때문에 수정 이전에 어디까지 DTO 및 Interface까지 영향을 끼치는지 확인하고 null 체크 테스트를 반드시 해야 합니다.
@Component
@RequiredArgsConstructor
@Slf4j
public class PostRetriever {
private final PostRepository postRepository;
//Interface 방식
public List<PostDTO> retrievePostByBoardUrl(String boardUrl) {
Pageable pageable = PageRequest.of(0, 10);
Page<PostMapping> PostList = postRepository.findPostByBoardUrlWithPagination(boardUrl, pageable);
return PostList.getContent()
.stream()
.map(post ->
PostDTO.builder()
.id(post.getId())
.title(post.getTitle())
.writer(post.getWriter())
.content(post.getContent())
.updatedAt(post.getUpdatedAt())
.commentCount(post.getCommentCount())
.build()
)
.toList();
}
//DTO 방식
public List<PostDTO> retrievePostByBoardUrl2(String boardUrl) {
Pageable pageable = PageRequest.of(0, 10);
Page<PostDTO> PostList = postRepository.findPostByBoardUrlWithPagination2(boardUrl, pageable);
return postList.getContent();
}