Open skarltjr opened 2 years ago
실수 복기.
ArticleRepositoryExtensionImpl
->
override fun findByIdWithBoardUserAndUserImage(id: Long): Article? {
return queryFactory.selectFrom(article)
.where(article.id.eq(id))
.join(article.board, board).fetchJoin()
.join(article.user, user).fetchJoin()
.join(user.image, image).fetchJoin()
.fetchOne()
}
처음에 게시글을 가져오면서 해당 게시글의 게시판, 작성자(User)와 유저의 프로필 이미지까지 한 번에 가져오고자 했다. 위 쿼리가 왜 동작하지 않았을까. 해당 id를 가진 게시글의 작성자의 프로필 사진(image)가 없다면?
즉 해당 id를 가진 게시글의 작성자의 프로필 사진(image)가 없다면 위 쿼리로 찾아올 수 없다.
해결
override fun findByIdWithBoardUserAndUserImage(id: Long): Article? {
return queryFactory.selectFrom(article)
.where(article.id.eq(id))
.join(article.board, board).fetchJoin()
.join(article.user, user).fetchJoin()
.leftJoin(user.image, image).fetchJoin()
.fetchOne()
}
잘못된 사용을 반성하고 올바르게 사용 실천해보기 상황
- 검색( 게시글 리스트 조회 )을 구현할 계획
- 검색은 해당 키워드를 제목 혹은 본문에 포함한 모든 article을 대상으로
- 이 때 no-offset 기반 페이징을 위해 lastArticleId를 전달받고 동적쿼리로 해당id가 null이면 리스트 첫 조회 / lastArticleId가 존재하면
lastArticleId의 게시글보다 이전에 생성된 게시글 최신순으로 n개 가져오기
문제점
회의에서 클라이언트와 기획이 게시글의 내용은 text-image-text-image part로 순서를 보장해주고 싶다고했다.
그래서 백엔드는 article 1 <- N textArticleUnit의 구조를 갖춰야했다. imageUnit도 마찬가지
★문제는 이 상황에서 위 검색을 구현해야하는 것.
하나의 article이 본문과 제목을 모두 갖고있는게 아니라
제목에 keyword를 포함한 article +. 본문 content에 keyword를 포함한 textUnit의 article을 대상으로 검색을 구현해야했다.
해결
leftjoin을 통해 article은 무조건 모두 가져오고 + 여기에 textUnit을 추가적으로 가져온 이 테이블을 대상으로 함으로써
아래 조건을 수행할 수 있고 검색을 구현할 수 있었다.
조건 1. 제목에 keyword를 포함한 article - 가능
조건 2. 본문 content에 keyword를 포함한 textUnit의 article을 대상으로 검색 - 가능
override fun searchArticlesWithKeywordAndLastArticleId(targetKeyword: String?, lastArticleId: Long?): List
private fun checkIfArticleContainKeyword(targetKeyword: String?): BooleanExpression? { if (targetKeyword == null || targetKeyword.equals("")) { return null } return textArticleUnit.content.containsIgnoreCase(targetKeyword) .or(checkIfArticleTitleContainKeyword(targetKeyword)) } private fun checkIfArticleTitleContainKeyword(targetKeyword: String?): BooleanExpression { return article.title.containsIgnoreCase(targetKeyword) } private fun checkLastArticleId(lastArticleId: Long?): BooleanExpression? { if (lastArticleId == null) { return null } return article.id.lt(lastArticleId) }
다만!
- 여기서 한 가지 짚고갈게있었다.
- 조건 1. 제목에 keyword를 포함한 article
- 조건 2. 본문 content에 keyword를 포함한 textUnit의 article
- 예를들어 제목에도 keyword를 갖고있고 본문에도 keyword가 포함된경우라면?
- 중복발생 -> distinct 활용
상황
기존
변경
기록
join 비교
a | b --+-- 3 | 3 4 | 4
left "outer" join