
댓글 목록을 볼 때 순수하게 댓글 목록(댓글 데이터)만 보는게 아니다.
Board정보(1), User정보(1), Reply정보(N)가 다 나와야함 -> 화면 확인하면 바로 알 수 있음

전략 1) ONE관계는 JOIN하고, MANY관계는 조회를 한 번 더 한 후 DTO 담기

보드와 유저는 ONE 관계 (JOIN 필요)
보드와 댓글은 MANY 관계 (SELECT를 한 번 더 함)
-> 담을 DTO 필요
1번 전략 설명
테스트 하려는데.... findByBoardId는 JpaRepository에 존재하지 않기 때문에 (기본 CRUD 아님) ReplyJPARepository에 만들어줘야 함
[ ReplyJPARepository ]

쿼리 메소드 아니니 @Query 적어주고
[ 테스트 하자 ]


조회 잘 됨! 이제 여기서 댓글만 JOIN하면 끝!
[ 문제 발생! return을 board, reply 이렇게 담을 수 없으니 DTO 필요! ]
[ BoardService ]


// 한 번에 캡쳐 할 수 없어서 나눠서 캡쳐함
board랑 replyList 둘 다 return 해줘야 하는데… 둘 다 return 하는 건 불가능!
때문에 둘을 담고 있는 DTO를 생성해서 한 번에 넘겨줘야 한다.
[ 쿼리문 조회 ]

이렇게 하면 밑의 결과가 나오는지 실습으로 확인 필요!


ONE관계는 join하고, MANY관계는 select 하고.. select가 2번 일어남 !
1번 전략은 쌤이 좋아하는 방식이다.
현재 댓글은 페이징 안 되어있는 상태. (실제 서비스에서는 댓글도 페이징이 되어야함)
join으로 해서 댓글을 페이징하는 쿼리가 엄청 힘들다.
join-join-join (3단)으로 페이징하는게 너무 어렵다!!
때문에 select 2번해서
List<Reply> replyList = replyJPARe~~~.findByBoardId(boardId) 를 페이징 하는게 낫다.
전략 2) MANY관계를 ‘양방향 매핑’ 하기 → @OneToMany 사용
[ Board테이블 ]

컬렉션은 필드로 받을 수 없어서 오류
[ @OneToMany 달아주자 ]

replies는 조회할 때, 담는 용도로만 사용. -> 애가 DB 필드가 되면 안됨!
-> @OneToMany 걸기
이 List<Reply> replies는 Board랑 뭘 관계하고 있지?
-> 변수명을 적어서 알려줘야 함
즉, FK의 주인이 누구인지 mappedBy로 설정해줘야 함
이때, Entity객체의 변수명을 적어주면 됨!
@Builder는 컬렉션은 허용하지 않기 때문에 List<Reply> replies는 빌더로 만들 수 없다!
@ManyToOne - EAGER 이 디폴트 전략
@OneToMany - LAZY가 디폴트 전략
쌤은 컬렉션 관계는 이렇게 조회를 한 번 더 해서 합치는 걸 선호한다. (1번 방법)
전략 3) 한방 JOIN
package shop.mtcoding.blog.board;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.Optional;
public interface BoardJPARepository extends JpaRepository<Board, Integer> {
@Query("select b from Board b join fetch b.user u where b.id = :id")
Optional<Board> findByIdJoinUser(@Param("id") int id);
//board에 다 담을 것
@Query("select b from Board b join fetch b.user u join fetch b.replies r where b.id = :id")
Optional<Board> findByIdJoinUserAndReplies(@Param("id") int id);
}
join 쿼리 작성
[ 테스트 ]
@DataJpaTest
public class BoardJPARepositoryTest {
@Autowired
private BoardJPARepository boardJPARepository;
@Autowired
private EntityManager em;
@Test
public void findByIdJoinUserAndReplies_test() {
//given
int id = 4;
//when
//옵셔널이라 오류가 나니까 .get 붙여줌. get는 있으니까 가져와! 라는 말
Board boards = boardJPARepository.findByIdJoinUserAndReplies(id).get();
//then
}

[ 댓글 목록 보기 3가지 전략 요약 ]
1. One 관계는 join하고, Many 관계는 Lazy Loading 한다. 그리고 DTO에 담는다.
select 칠 필요 없음. 자기가 쳐줌. 애를 디폴트로 사용하자!~!
(통신 1번 / 12회 조회)
2. One 관계는 join하고, Many 관계를 페이징 (or 복잡한 무언가) 해야 된다면
select를 직접 쿼리를 만들어서 2번 조회하자 (Lazy Loading으로 페이징 안됨!)
(통신 2회 / 12회 조회)
3. One 관계와 Many 관계를 한 방에 JOIN 한다.
(28회 조회)
현재 프로젝트할 때에는 1번을 써라.
근데 댓글을 페이징 해야한다던지.. 그러면 2번을 사용
→ 사실 이걸 써라! 라는 답이 없긴 함.
어떤 전략을 선택해야 할 지 결정할 수 있는 게 중요! (상황에 따라 다르기 때문)
속도, 성능 고려 … 데이터에 따라 고려, 페이징 되었을 때 뭐 이런 것도 고려…해서 공부를 하자^^
Share article