[JPA] Spring Data JPA에서 바로 DTO를 받아보자
게시판에서 좋아요, 싫어요 기능을 구현하려고 하고 있다. Spring Data JPA를 활용해서 나는 인터페이스만 구현해서 아주 편안하게 값을 가져와서 활용하고 있다. 쉬운 쿼리들은 메서드 네임만 잘 조합해도 되는데, 나는 이제 좋아요, 싫어요 개수를 구하고 싶다. 즉, 쿼리에서 count()를 이용해서 갖고 올려고 하는 것이다. 찾아보면 메서드 네임으로도 있을거 같긴 한데.. 일단은 JPQL을 통해서 갖고오는 방법을 정리해 보겠다.
대학 팀플들 땜에 프로젝트 글 정리를 못했는데, 조만간 다 정리해서 올리겠다 ㅠㅠ
좋아요 엔티티
먼저 좋아요 엔티티를 구성했다.
@Getter
@NoArgsConstructor
@Entity
public class Likes {
@Id
@GeneratedValue
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id")
private Board board;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private Account account;
@Enumerated(value = EnumType.STRING)
private LikeStatus status;
@Builder
public Likes(Board board, Account account, LikeStatus status) {
this.board = board;
this.account = account;
this.status = status;
}
public void setAccountBoard(Account account, Board board) {
board.getLikes().add(this);
account.getLikes().add(this);
this.board = board;
this.account = account;
}
}
좋아요 엔티티는 사용자와 게시판과 1:N 관계로 풀어냈다. 사용자 한 명은 여러 게시판 좋아요 할 수 있기 때문이다.
그리고 setAccountBoard 메서드를 만들어 연관관계 편의 메서드를 구현해주었다.
그리고 status를 ENUM을 구현해 LIKE와 DISLIKE를 선택하게 해줄 것이다.
내가 생각한 방식이 괜찮은 방식인진 모르겠으나 일단 밀고 나가보겠다. 더 좋은 구현이 있으면 댓글 부탁드립니다! :)
주의)
이건 좀 허무할 수도 있는데, 엔티티명을 처음에는 Like로 짓고 코드를 돌렸다. 그랬더니 DDL CREATE 부분에서 자꾸 에러가 뜨는 것이다. 왜일까 찾아보니 like가 sql에서 사용하는 예약어이기 때문에 충돌난 것이다. 나처럼 뻘짓 일으키지 마시라 적어둔다.
좋아요 레포지토리 생성
먼저 좋아요를 조회할 수 있는 레포지토리를 생성할 것이다. Spring Data Jpa를 쓸 것이기에, 인터페이스를 생성하고 상속받으면 된다.
public interface LikesRepository extends JpaRepository<Likes, Long> {
}
이렇게만 해두어도, 기본적인 CRUD는 다 할 수 있다. 우리 개발자는 이를 통해 아주 손쉽게 데이터를 다룰 수 있다.
여기서 이제 Data JPA에서 제공하는 컨벤션을 잘 활용하면 원하는 대로 쿼리를 보낼 수 있게 해준다. 가령 특정 보드의 좋아요만 가져오고 싶다. 하면 다음과 같이 메서드를 적어 주면 된다.
List<Likes> findAllByBoard(Board board);
테스트도 돌려보자
@Test
@DisplayName("특정 보드 좋아요 갖고오기")
void getLikeByBoard() throws Exception {
// given
Board board = boardRepository.findAll().get(0);
// when
List<Likes> likes = likesRepository.findAllByBoard(board);
// then
for (Likes like : likes) {
System.out.println(like.getStatus());
}
}
그러면 저 게시판에 있는 좋아요와 싫어요를 볼 수 있다.
근데 나는 저 좋아요/싫어요의 수를 보고 싶은 것이다. 물론 자바 코드를 활용해서도 값을 구할 수 있겠지만, DB에 있는 기능을 써야 또 멋있어 보이지 않을까? ㅋㅋㅋ 암튼 그렇기에 jpql을 써서 구해보자. 그 전에 sql로 잘 되는지 부터 봐봐자.
SELECT status, COUNT(status) AS cnt FROM likes WHERE board_id=6 GROUP BY status;
GROUP BY를 써서 status끼리 묶어 두었다. 이를 이제 JPQL로 적용해보자.
@Query("SELECT COUNT(l.status) FROM Likes as l WHERE l.board=:board GROUP BY l.status")
List<Long> findLikeDislikeCountPrintLong(@Param("board") Board board);
테스트를 돌려보면 [5, 10]을 받아온다. 물론 이 리스트 그대로 활용할 수도 있겠지만, DISLIKE와 LIKE 순서가 바뀐다면? 그러면 화면에서 잘못되게 될 수도 있기에 이것을 status와 count를 가진 DTO로 받아오게끔 처리하고 싶다. 그럴 땐 다음과 같은 JPQL을 짜주면 된다.
@Query("SELECT new com.somefood.board.web.dto.LikeCountDto(l.status, COUNT(l.status)) FROM Likes as l WHERE l.board=:board GROUP BY l.status")
List<LikeCountDto> findLikeDislikeCount(@Param("board") Board board);
new를 할 때, 패키지부터 시작해서 Dto클래스를 입력해주고 여기 안에 내가 의도한 값들을 넣어주면 된다. 조금 지저분해 보일 수도 있지만, 이것이 최선의 방법이기에 써보자.
자, 이렇게 하면 DTO로 내가 원하는 값을 뽑을 수 있고, 나는 이걸로 이제 예쁘게 화면을 그려주면 된다. 이후에도 더 좋은 방법이 있는지 찾아봐야겠다.