⏱️ 오늘의 일정 ⏱️
9:00 ~ 10:00 - 팀 회의
10:00 ~ 11:00 - 알고리즘 문제 풀기
11:00 ~ 13:00 - 플러스 주차 개인 과제
13:00 ~ 14:00 - 점심시간
14:00 ~ 17:30 - 플러스 주차 개인 과제
17:30 ~ 18:00 - 팀 회의
18:00 ~ 19:00 - 저녁 시간
19:00 ~ 21:00 - 플러스 주차 개인 과제
Query DSL
많은 도움이 된 곳
의존성 추가
// Query DSL
implementation 'com.querydsl:querydsl-jpa:5.0.0:jakarta'
annotationProcessor "com.querydsl:querydsl-apt:${dependencyManagement.importedProperties['querydsl.version']}:jakarta"
annotationProcessor "jakarta.annotation:jakarta.annotation-api"
annotationProcessor "jakarta.persistence:jakarta.persistence-api"
빌드
Q클래스를 통해 동작하기 때문에 사용에 앞서 build를 진행해야 한다.
순서대로 눌러준다.
설계
public interface BoardRepositoryCustom {
Optional<BoardResponseDto> findWithLikeCountById(Long id);
}
기존 JPARepository와는 별개의 레포지토리 인터페이스를 만든다.
이름은 편의 상 뒤에 Custom을 붙였다.
구현 할 메서드를 작성한다.
@Repository
@RequiredArgsConstructor
public class BoardRepositoryCustomImpl implements BoardRepositoryCustom {
private final JPAQueryFactory queryFactory;
@Override
public Optional<BoardResponseDto> findWithLikeCountById(Long id) {
return Optional.ofNullable(queryFactory
.select(new QBoardResponseDto(
board.user.nickname,
board.id,
board.title,
board.contents,
likeBoard.count().intValue(),
board.createdAt,
board.modifiedAt
))
.from(board)
.leftJoin(board.likeBoards, likeBoard)
.where(board.id.eq(id))
.groupBy(board.id)
.fetchOne()
);
}
}
그리고 이 인터페이스를 구현 한 클래스를 만들자.
이 클래스에서 Query DSL을 사용한다.
그럼 이 클래스를 레포지토리로 바로 쓰는가?
아마 그럴 수도 있지만 JPA의 기능도 이용할 수 있으면 더 좋지 않을까?
public interface BoardRepository extends JpaRepository<Board, Long>, BoardRepositoryCustom {
List<Board> findAllByUserIdInOrderByCreatedAtDesc(List<Long> followingUserId);
// ...
}
이렇게 기존 많이 보던 JpaRepository를 상속한 레포지토리 인터페이스에 방금 만든 커스텀 레포지토리 인터페이스도 상속시킨다.
이러면 위 BoardRepository를 사용하는 것 만으로 JPA 메서드도, QueryDSL 메서드도 사용할 수 있다.
어떻게?
애플리케이션 시작 시 JPA가 상속한 기능들을 전부 구현시킨다.
우리는 BoardRepositoryCustom 구현체를 만들어 놨기 때문에 JPA가 이를 참고해 같이 구현시켜 준다.
SimpleJpaRepository와 함께.
쿼리 결과 DTO로 받기
SQL에서 쿼리를 날릴 때는 COUNT(*)등 원하는 칼럼을 자유자재로 뽑아낼 수 있다.
그럼 원하는 칼럼들을 필드로 갖는 DTO를 만들어 결과를 받을 수 없을까?
물론 여러가지 방법이 있지만 이 글에서 추천하는 것은 @QueryProjection을 이용한 방법이다.
@QueryProjection
public CommentResponseDto(Long userId, Long boardId, String contents, Integer likeCount) {
this.userId = userId;
this.boardId = boardId;
this.contents = contents;
this.likeCount = likeCount;
}
생성자에 @QueryProjection 어노테이션을 달아준다.
그러면 Dto도 Q클래스로 뽑아지게 된다.
queryFactory
.select(new QCommentResponseDto(
comment.user.id,
comment.board.id,
comment.contents,
likeComment.count().intValue()
))
.from(comment)
.leftJoin(comment.likeComments, likeComment)
.where(comment.id.eq(id))
.groupBy(comment.id)
.fetchOne()
select 구문에서 이 Q클래스 객체를 생성할 수 있다.
참고로 Q클래스를 만들 때마다 build 작업을 해야 한다.
쿼리를 짜는 법은 직관적이긴 하지만,
나는 한 번 SQL 문법으로 쿼리를 작성하고 그걸 다시 QueryDSL로 변환하여 사용하고 있다.
처음부터 QueryDSL로 짜는 건 아직 좀 어렵다 ㅋㅋㅋ
'공부 기록 > 내배캠Java_5기' 카테고리의 다른 글
[내배캠][TIL] 60일 차 - 목요일, PR 코드리뷰와 React? (0) | 2024.07.11 |
---|---|
[내배캠][TIL] 59일 차 - 수요일, 심화 프로젝트와 GitHub 협업 (0) | 2024.07.10 |
[내배캠][TIL] 49일 차 - 수요일, 플러스 주차 시작 (0) | 2024.06.26 |
[내배캠][TIL] 48일 차 - 화요일, 프로젝트 회고 (0) | 2024.06.26 |
[내배캠][TIL] 47일 차 - 월요일, 인터넷 끊김 이슈 (0) | 2024.06.25 |