๐ DATE : 2023.01.10 TUE
DB ์คํฐ๋ ์์ ๋ฐ Querydsl ๊ณต๋ถ
์ค๋๋ถํฐ ๋ฐ์ดํฐ ๋ฒ ์ด์ค ์คํฐ๋๋ฅผ ์์ํ๋ค.
์์ง์ ์ฒ์์ด๋ผ ๊ท์น์ด๋ ๋ฐฉํฅ์ฑ์ ๋ํ ์๊ธฐ๋ฅผ ๋ง์ด ๋๋์๋ค.
์ด๋ค ๋๋น๋ฅผ ๋จผ์ ๊ณต๋ถํ ์ง, ์ด๋ป๊ฒ ๊ณต๋ถํ ์ง์ ๋ํด์ ์ด์ผ๊ธฐ๋ฅผ ํ์๋ค.
ํด๋น ์ด์ผ๊ธฐ ์ ์ ๋ฏธ๋ฆฌ ํ์ด๋ณด๊ธฐ๋ก ํ ๋ฌธ์ ๋ค์ ํ์ด๋ณด์๋ค.
๊ทธ ๊ณผ์ ์์ WHERE๊ณผ HAVING์ ๋ํด ์ด์ผ๊ธฐ๋ฅผ ๋๋์๋ค.
์ด ๋ถ๋ถ์ ๋ด๊ฐ ๋ค์ ๊ณต๋ถํด์ ์ ๋ฆฌํด์ ๋ธ๋ก๊น ์ ํ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ์๋ค.
๊ทธ๋ฆฌ๊ณ ์ด์ ์ ์ด์ด Querydsl์ ๊ณต๋ถํ๊ณ ์ฌ์ฉํด๋ณด๊ณ ์๋ค.
์ด์ MutliResponseDto๋ฅผ ๋ง๋ค์ด ํ์ด์ง ์ ๋ณด๊น์ง ๋๊ฒจ๋ณด๊ณ ์์๋ค.
๊ทผ๋ฐ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
์๋์ ์ฌ์ง์ฒ๋ผ page ์ ๋ณด์ totalElements, totalPages๊ฐ ์๋ชป ์ถ๋ ฅ๋๋ ๊ฒ์ด๋ค.
์๋๋๋ก๋ผ๋ฉด, page๋ 3์ด์ด์ผํ๊ณ totalElements๋ 14๊ฐ์ด๋ฉฐ totalPages๋ 3์ด ์ถ๋ ฅ์ด ๋์ด์ผ ํ๊ธฐ ๋๋ฌธ์ด๋ค.
public class CustomCommentRepositoryImpl implements CustomCommentRepository {
private final JPAQueryFactory queryFactory;
public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {
List<CommentDto.Response> result = queryFactory
.select(Projections.fields(CommentDto.Response.class,
comment.board.boardId,
comment.commentId,
comment.nickName,
comment.content,
comment.createdAt,
comment.modifiedAt))
.from(comment)
.where(comment.board.boardId.eq(boardId))
.orderBy(comment.commentId.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
return new PageImpl<>(result);
}
}
๊ณฐ๊ณฐํ ์ฝ๋๋ฅผ ๋ณด๋ฉฐ ์๊ฐํด๋ณด๋, ํ์ด์ง์ ๋ํ ์ ๋ณด๊ฐ ์ ๋ค์ด๊ฐ์ง ์์ ๊ฒ์ด ์๋๊น ์ถ์๋ค.
๊ทธ๋์ PageImpl ํด๋์ค๋ฅผ ๋ณด๊ณ pageable ์ ๋ณด๋ฅผ ๋ฃ์ด์ฃผ์๋ค.
๊ทธ๋ฌ๋๋ ๋ง์ง๋ง์ธ ์ธ๋ฒ์งธ ํ์ด์ง์์๋ ์ ์ถ๋ ฅ์ด ๋์๋ค.
ํ์ง๋ง! ๋ ๋ฒ์งธ ํ์ด์ง๋ฅผ ๋ณด๋ฉด ์ ๋ ๊ฒ์ด ์๋์๋ค.
์๋์ ์ค๋ฅธ์ชฝ ์ฌ์ง์ ์ฐธ๊ณ ํ๋ฉด totalElements๊ฐ 10๋ก ๋์ค๋ ๊ฒ์ ์ ์ ์๋ค.
public class CustomCommentRepositoryImpl implements CustomCommentRepository {
private final JPAQueryFactory queryFactory;
public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {
List<CommentDto.Response> result = queryFactory
.select(Projections.fields(CommentDto.Response.class,
comment.board.boardId,
comment.commentId,
comment.nickName,
comment.content,
comment.createdAt,
comment.modifiedAt))
.from(comment)
.where(comment.board.boardId.eq(boardId))
.orderBy(comment.commentId.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
/* pageable ์ ๋ณด ์ถ๊ฐ ๋ฐ ๋ฆฌ์คํธ ์ฌ์ด์ฆ ์ถ๊ฐ */
return new PageImpl<>(result, pageable, result.size());
}
}
๊ทธ๋์ ๊ตฌ๊ธ๋ง์ ํด๋ณด์๋ค.
๊ทธ๋ฌ๋ฉด์ SpringFramework์ ํ์ด์ง ์ฒ๋ฆฌ๋ฅผ ๋์์ฃผ๋ ํด๋์ค๊ฐ ์๋ค๋ ๊ฒ์ ์์๋ค.
๋ฐ๋ก PageableExecutionUtils์ด์๋ค.
๊ทธ๋์ ์ฐพ์๋ณธ ํ ํด๋น ํด๋์ค๋ฅผ ์ ์ฉ์์ผ์ฃผ์๋ค.
ํ์ง๋ง ํด๋น ๋ฌธ์ ๋ ํด๊ฒฐ๋์ง ์์๋ค.
์กฐ๊ธ ๋ ์์๋ฅผ ์ฐพ์๋ณธ ๊ฒฐ๊ณผ JPAQuery๋ฅผ ํตํด ํ์ด์ง ๊ฐ์ ์ฐพ์ ์ ์๋ ์์๋ฅผ ๋ฐ๊ฒฌํ์๋ค.
๊ทธ๋์ ํด๋น ๋ถ๋ถ์ ์ ์ฉ์์ผ ๋ณธ ๊ฒฐ๊ณผ ํด๊ฒฐ์ด ๋์๋ค.
public class CustomCommentRepositoryImpl implements CustomCommentRepository {
private final JPAQueryFactory queryFactory;
public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {
List<CommentDto.Response> result = queryFactory
.select(Projections.fields(CommentDto.Response.class,
comment.board.boardId,
comment.commentId,
comment.nickName,
comment.content,
comment.createdAt,
comment.modifiedAt))
.from(comment)
.where(comment.board.boardId.eq(boardId))
.orderBy(comment.commentId.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize())
.fetch();
/* ์๋์ ์ฝ๋๋ ๊ฐ๋ฅ
JPAQuery<Comment> total = queryFactory.selectFrom(comment)
.where(comment.board.boardId.eq(boardId));
*/
JPAQuery<CommentDto.Response> total = queryFactory
.select(Projections.fields(CommentDto.Response.class,
comment.board.boardId,
comment.commentId,
comment.nickName,
comment.content,
comment.createdAt,
comment.modifiedAt))
.from(comment)
.where(comment.board.boardId.eq(boardId));
return PageableExecutionUtils.getPage(result, pageable, () -> total.fetch().size());
}
}
์ฌ๊ธฐ์ ๋ ๋ค๋ฅธ ์๋ฌธ์ด ์๊ฒผ๋ค.
fetch๋ฅผ ํ๊ณ size๋ฅผ ๊ตฌํ๋ ๊ฒ์ด๋ฉด, JPAQuery๋ฅผ ์ด์ฉํด ๋ค ๊ฐ๋ฅํ์ง ์์๊น ํ๋ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ด์ํ๊ฒ๋ ๊ทธ๋ ๊ฒ ํ๋ฉด, ์๊น ์๊ฒผ๋ ๋ฌธ์ ์ฒ๋ผ ๋ ๋ฒ์งธ ํ์ด์ง์์ ์ ๋๋ก ์ถ๋ ฅ๋์ง ์๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์๊ณ ,
์ฌ์ง์ด๋ totalPages๋ 2ํ์ด์ง๋ก๋ง ๋จ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ์๋ค.
public class CustomCommentRepositoryImpl implements CustomCommentRepository {
private final JPAQueryFactory queryFactory;
public CustomCommentRepositoryImpl(JPAQueryFactory queryFactory) {
this.queryFactory = queryFactory;
}
@Override
public Page<CommentDto.Response> findComment(long boardId, Pageable pageable) {
JPAQuery<CommentDto.Response> total = queryFactory
.select(Projections.fields(CommentDto.Response.class,
comment.board.boardId,
comment.commentId,
comment.nickName,
comment.content,
comment.createdAt,
comment.modifiedAt))
.from(comment)
.where(comment.board.boardId.eq(boardId))
.orderBy(comment.commentId.desc())
.offset(pageable.getOffset())
.limit(pageable.getPageSize());
return PageableExecutionUtils.getPage(total.fetch(), pageable, () -> total.fetch().size());
}
}
์์ง ๊ฐ์๋ฅผ ์ด ๊ณณ๊น์ง ๋ค ๋ฃ์ง ๋ชปํ๊ธฐ ๋๋ฌธ์ ์กฐ๊ธ ๋ ๊ณต๋ถํด๋ณด๊ณ , ์ด์ ๋ฅผ ์ฐพ๋๋ค๋ฉด ํ์คํ ๊ธฐ๋ก์ ํด๋์ด์ผ ๊ฒ ๋ค!
๋๊ธ