xxxQueryRepository 사용법!
그냥 Repository에서 조인을 해서 사용할 수도 있겠지만
네이티브 스칼라 서브쿼리를 사용해서 데이터를 뽑아올 수도 있다
(→JPQL이 어려우면 이걸 사용하기. MyBatis 사용법과 비슷)
각 게시글마다의 댓글갯수를 뽑아보자.
게시글 더미 5개 추가
insert into board_tb(title, content, created_at, user_id)
values ('제목1', '내용1', now(), 1);
insert into board_tb(title, content, created_at, user_id)
values ('제목2', '내용2', now(), 1);
insert into board_tb(title, content, created_at, user_id)
values ('제목3', '내용3', now(), 2);
insert into board_tb(title, content, created_at, user_id)
values ('제목4', '내용4', now(), 2);
insert into board_tb(title, content, created_at, user_id)
values ('제목5', '내용5', now(), 2);
insert into board_tb(title, content, created_at, user_id)
values ('제목6', '내용6', now(), 1);
insert into board_tb(title, content, created_at, user_id)
values ('제목7', '내용7', now(), 1);
insert into board_tb(title, content, created_at, user_id)
values ('제목8', '내용8', now(), 2);
insert into board_tb(title, content, created_at, user_id)
values ('제목9', '내용9', now(), 2);
insert into board_tb(title, content, created_at, user_id)
values ('제목10', '내용10', now(), 2);
- Mysql 설치되어있으면 거기 연결해서 쿼리 연습하기 ( h2는 쿼리연습하기엔 불편 )
- application.properites 랑 build.gradel 에도 추가되어있어야 함
spring.datasource.driver-class-name
이 부분도 바꿔야 함

우리가 뽑아내야 하는 데이터! → pk 게시글제목 해당게시글의댓글갯수
→ 이걸 담는 Entity가 없다.!
일단 댓글 갯수를 뽑아보자.

count 안에는 다른 column말고 보통 “id”를 넣는다!
게시글 5번의 댓글 갯수를 reply_tb에서 가지고 옴.
→ 여기서 주목해야 할 것은 row가 1개인 “스칼라” 라는 것!!!!!!!

이게 스칼라 서브쿼리 임
→ 스칼라인 쿼리를 서브쿼리로 넣어주는 개념 ? 인듯
스칼라의 의미는 1개 → .을 의미한다.
row가 2개이면 넣을 수 없다!
스칼라는 무조건 1줄 이 나와야 하고, 컬럼도 1개여야 한다.
→ 컬럼이 2개면 2차원이여서 안됨

이건 행이 3개 → 결과가 3건

원자성이 위배되어서 할 수 없다.

from 부터 실행하니까 bt.id라고 해도 이해할 수 있다.

이게 스칼라성 쿼리임
이런 쿼리는 jpql로 못짬
쿼리 복사해서 QueryRepository “”” 안에 넣어주기
package org.example.springv3.board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
@RequiredArgsConstructor
@Repository
public class BoardQueryRepository {
private final EntityManager em;
// 네이티브 쿼리
// 길거 같아서 쌍따옴표 3개 씀
public void select(){
String sql = """
select id, title, (select count(id) from reply_tb where board_id = bt.id) count
from board_tb bt;
""";
Query query = em.createNativeQuery(sql);
}
}
스. 칼. 라. 성 쿼리!!!! 다!!!
Join으로도 할 수 있지만 이게 더 쉬운 방법!
자 이제 테스트

여기까지 작성함.
Reposiutory에 점찌;ㄱ어두고

제이쿼리에서 네이티브쿼리를 썼을때
자바오브젝트로
바꿔서 나오게 해주는 라이브러리



++
dataTransferObject는 클라이언트와 컨트롤러 사이에 있다.
RequestDTO와 ResponseDTO를 전달해주는 역할을 함
DTO는 원래 클라이언트한테 전송해주는 데이터임.
DB에서 가져와서 담는거는 다른거다! VO라고 부르자.
근데 화사가면 다 DTO라고 부른다.ㅜ
디비에있는 데이터를 들고와서 Model에 담는다.
클래스 vs 테이블
DB에 있는걸 가져와서 자바세상의 객체에 담는걸 모델링이라고 한다.
설계도 세상의 데이터를 실제 세상에 만드는 것을 모델링이라고 한다.
같은 개념이다.
모델링하니까 튀어나온 데이터를 “모델”이라고 한다.
DTO → Data Trasnfer Object → 화면에 필요한 데이터만 들고 있음!
우리는 DB → Repository 에 가져오는게 이미 클라이언트가 필요한 것만 가져왔으니까
변형없이 클라이언트에게 줄거니까 VO가 아니라 DTO라고 부르는게 원래 맞다.
이런걸 해주게 하는 쿼리를 “한방쿼리”라고 한다.
이런건 Serive 레이어도 필요없다.

만들기 ( 나중에 위치 옮길거임 )

이걸 받을 DTO(vO)를 만들어야 한다.

1건이면 unique
지금은 여러건이니까 list

완성하고 테스트하자

→ 풀 생성자가 있어야 파싱해주는데, 풀 생성자가 지금 없어서 에러 나는 것
new해서 contructor를 때려서 값을 넣는 방식
DB에서 카운트 친거는 Long 타입으로 받는군.
수정하자!

package org.example.springv3.board;
import lombok.Data;
@Data // getter, setter, toString
public class BoardListVO {
private Integer id;
private String title;
private Long count;
public BoardListVO(Integer id, String title, Long count) {
this.id = id;
this.title = title;
this.count = count;
}
}

수정하고 다시 테스트 하니 잘 된다 : )
이렇게 네이티브 쿼리 사용해서 QLRM을 파싱하려면
일단 gradle에 의존성 추가 해놓고
VO에는 1. FULL생성자가 있어야 한다. 2. 타입 잘 봐야 한다.
리팩토링 진행

이거 VO로 빼면 지저분 해져서
그냥 Response안에 DTO로 넣기!
그리고 BoardListVO 삭제

옮기면서 클래스명 ListDTO로 변경함

BoardQueryRepository 도 BoardResponse.ListDTO를 return 하는 걸로 수정
package org.example.springv3.board;
import jakarta.persistence.EntityManager;
import jakarta.persistence.Query;
import lombok.RequiredArgsConstructor;
import org.qlrm.mapper.JpaResultMapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@RequiredArgsConstructor
@Repository
public class BoardQueryRepository {
private final EntityManager em;
// 네이티브 쿼리
// 길거 같아서 쌍따옴표 3개 씀
public List<BoardResponse.ListDTO> selectV1(){
String sql = """
select id, title, (select count(id) from reply_tb where board_id = bt.id) count
from board_tb bt;
""";
Query query = em.createNativeQuery(sql);
JpaResultMapper mapper = new JpaResultMapper();
List<BoardResponse.ListDTO> boardList = mapper.list(query, BoardResponse.ListDTO.class);
return boardList;
}
}

package org.example.springv3.board;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.context.annotation.Import;
import java.util.List;
@Import(BoardQueryRepository.class) // JPA Repository 가 아니어서 import 필요함
@DataJpaTest
public class BoardQueryRepositoryTest {
@Autowired
private BoardQueryRepository boardQueryRepository;
@Test
public void selectV1_test(){
//given
// 여기 들어갈게 없음
//when ->
List<BoardResponse.ListDTO> boardList = boardQueryRepository.selectV1();
//eye
System.out.println(boardList);
}
}
BoardQueryRepositoryTest 도 수정해서 실행하면 콘솔에 결과가 잘 나옴
Share article