From 8a6cd8c90c5215cefd50fd86ae30885bd006b0a8 Mon Sep 17 00:00:00 2001 From: kkw610 Date: Tue, 2 Jun 2026 15:23:03 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20=EC=A7=88=EB=AC=B8=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=20=EC=A2=8B=EC=95=84=EC=9A=94=20=EC=97=AC=EB=B6=80=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=EB=A5=BC=20N+1=EC=97=90=EC=84=9C=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EB=8B=A8=EA=B1=B4=20=EC=BF=BC=EB=A6=AC=EB=A1=9C=20?= =?UTF-8?q?=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../repository/QuestionLikeRepository.java | 11 +++++ .../question/service/QuestionService.java | 42 +++++++++++++------ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/backend/src/main/java/com/example/Piroin/project/domain/question/repository/QuestionLikeRepository.java b/backend/src/main/java/com/example/Piroin/project/domain/question/repository/QuestionLikeRepository.java index 9fb38f3..2d3cb3a 100644 --- a/backend/src/main/java/com/example/Piroin/project/domain/question/repository/QuestionLikeRepository.java +++ b/backend/src/main/java/com/example/Piroin/project/domain/question/repository/QuestionLikeRepository.java @@ -4,7 +4,10 @@ import com.example.Piroin.project.domain.question.entity.QuestionLike; import com.example.Piroin.project.domain.user.entity.User; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; +import java.util.List; import java.util.Optional; public interface QuestionLikeRepository extends JpaRepository { @@ -19,4 +22,12 @@ public interface QuestionLikeRepository extends JpaRepository findLikedQuestionIdsByQuestionIdsAndUser( + @Param("questionIds") List questionIds, + @Param("user") User user + ); } \ No newline at end of file diff --git a/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java b/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java index 1f0fa78..af58000 100644 --- a/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java +++ b/backend/src/main/java/com/example/Piroin/project/domain/question/service/QuestionService.java @@ -27,7 +27,9 @@ import java.util.Comparator; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.Map; +import java.util.HashSet; import java.util.stream.Collectors; @Service @@ -589,7 +591,7 @@ private QuestionResDTO.UnderstandingCheckResponse toUnderstandingCheckResponse( private QuestionResDTO.QuestionGroupsResponse getQuestionGroups(StudySession session, User loginUser) { List questions = questionRepository.findBySessionAndDeletedAtIsNull(session); - QuestionSummaryContext summaryContext = getQuestionSummaryContext(questions); + QuestionSummaryContext summaryContext = getQuestionSummaryContext(questions, loginUser); List popularQuestions = questions.stream() .filter(q -> !q.getIsResolved() && q.getLikeCount() >= POPULAR_LIKE_THRESHOLD) @@ -616,7 +618,7 @@ private QuestionResDTO.QuestionSummaryResponse toQuestionSummaryResponse ( User loginUser ) { Long questionId = question.getId(); - boolean isLiked = questionLikeRepository.existsByQuestionAndUser(question, loginUser); + boolean isLiked = summaryContext.likedQuestionIds().contains(questionId); boolean isMine = question.getUser().getId().equals(loginUser.getId()); return new QuestionResDTO.QuestionSummaryResponse( questionId, question.getContent(), question.getImageUrl(), @@ -632,9 +634,9 @@ private QuestionResDTO.QuestionSummaryResponse toQuestionSummaryResponse ( ); } - private QuestionSummaryContext getQuestionSummaryContext(List questions) { + private QuestionSummaryContext getQuestionSummaryContext(List questions, User loginUser) { if (questions.isEmpty()) { - return new QuestionSummaryContext(Map.of(), Map.of()); + return new QuestionSummaryContext(Map.of(), Map.of(), Set.of()); } List questionIds = questions.stream() @@ -651,14 +653,17 @@ private QuestionSummaryContext getQuestionSummaryContext(List question questionCommentRepository.findPreviewCommentsByQuestionIds(questionIds) .forEach(row -> { Question question = questionsById.get(row.getQuestionId()); - if (question == null) { - return; - } + if (question == null) return; previewComments.computeIfAbsent(row.getQuestionId(), key -> new ArrayList<>()) .add(toPreviewCommentResponse(question, row)); }); - return new QuestionSummaryContext(commentCounts, previewComments); + // 좋아요 여부를 질문마다 조회하는 대신 한 번에 배치 조회한다. + Set likedQuestionIds = new HashSet<>( + questionLikeRepository.findLikedQuestionIdsByQuestionIdsAndUser(questionIds, loginUser) + ); + + return new QuestionSummaryContext(commentCounts, previewComments, likedQuestionIds); } private QuestionResDTO.PreviewCommentResponse toPreviewCommentResponse( @@ -692,16 +697,26 @@ private String getPreviewDisplayName(Question question, QuestionCommentRepositor private void publishCommentCreatedEventAfterCommit(Question question) { Long sessionId = question.getSession().getId(); Long questionId = question.getId(); - QuestionSummaryContext summaryContext = getQuestionSummaryContext(List.of(question)); - // 프론트가 전체 목록을 다시 조회하지 않고 해당 질문만 갱신할 수 있는 최소 데이터만 보낸다. + // 이벤트 발행용이라 좋아요 여부가 필요 없으므로 댓글 수/미리보기만 직접 조회 + List questionIds = List.of(questionId); + + Map commentCounts = new HashMap<>(); + questionCommentRepository.countByQuestionIds(questionIds) + .forEach(row -> commentCounts.put(row.getQuestionId(), Math.toIntExact(row.getCommentCount()))); + + Map> previewComments = new HashMap<>(); + questionCommentRepository.findPreviewCommentsByQuestionIds(questionIds) + .forEach(row -> previewComments.computeIfAbsent(row.getQuestionId(), key -> new ArrayList<>()) + .add(toPreviewCommentResponse(question, row))); + QuestionResDTO.CommentCreatedEvent event = new QuestionResDTO.CommentCreatedEvent( "COMMENT_CREATED", sessionId, questionId, question.getIsResolved(), - summaryContext.commentCounts().getOrDefault(questionId, 0), - summaryContext.previewComments().getOrDefault(questionId, List.of()) + commentCounts.getOrDefault(questionId, 0), + previewComments.getOrDefault(questionId, List.of()) ); publishAfterCommit(() -> questionEventService.publishCommentCreated(sessionId, event)); @@ -774,7 +789,8 @@ public void afterCommit() { private record QuestionSummaryContext( Map commentCounts, - Map> previewComments + Map> previewComments, + Set likedQuestionIds ) { } }