-
Notifications
You must be signed in to change notification settings - Fork 0
[refactor/#91] 문항세트 조회 api 리팩토링 #93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
package com.moplus.moplus_server.domain.problemset.repository; | ||
|
||
import static com.moplus.moplus_server.admin.publish.domain.QPublish.*; | ||
import static com.moplus.moplus_server.domain.concept.domain.QConceptTag.*; | ||
import static com.moplus.moplus_server.domain.problem.domain.problem.QProblem.*; | ||
import static com.moplus.moplus_server.domain.problem.domain.childProblem.QChildProblem.*; | ||
|
||
import com.moplus.moplus_server.admin.problemset.dto.response.ProblemSetGetResponse; | ||
import com.moplus.moplus_server.admin.problemset.dto.response.ProblemSummaryResponse; | ||
import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; | ||
import com.querydsl.core.Tuple; | ||
import com.querydsl.jpa.impl.JPAQueryFactory; | ||
import java.time.LocalDate; | ||
import java.util.*; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Repository; | ||
|
||
@Repository | ||
@RequiredArgsConstructor | ||
public class ProblemSetGetRepositoryCustom { | ||
|
||
private final JPAQueryFactory queryFactory; | ||
|
||
public ProblemSetGetResponse getProblemSet(ProblemSet problemSet) { | ||
// 발행 날짜 조회 쿼리 | ||
List<LocalDate> publishedDates = queryFactory | ||
.select(publish.publishedDate) | ||
.from(publish) | ||
.where(publish.problemSetId.eq(problemSet.getId())) | ||
.fetch(); | ||
|
||
// 문항 및 새끼문항 조회 | ||
List<Tuple> problemData = queryFactory | ||
.select( | ||
problem.id, | ||
problem.problemCustomId.id, | ||
problem.title.title, | ||
problem.memo, | ||
problem.mainProblemImageUrl | ||
) | ||
.from(problem) | ||
.leftJoin(problem.childProblems, childProblem) // 자식 문제 JOIN | ||
.where(problem.id.in(problemSet.getProblemIds())) | ||
.distinct() | ||
.fetch(); | ||
|
||
// 문항 및 새끼 문항의 개념 태그 조회 | ||
List<Long> allProblemIds = problemSet.getProblemIds(); // 문제 ID 목록 | ||
List<Long> childProblemIds = queryFactory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 위에서 problem과 childproblem을 fetch join해와서 한번더 조회를 하지않아도 될것 같아요 |
||
.select(childProblem.id) | ||
.from(problem) | ||
.join(problem.childProblems, childProblem) | ||
.where(problem.id.in(allProblemIds)) | ||
.fetch(); | ||
|
||
Set<Long> allProblemAndChildProblemIds = new HashSet<>(allProblemIds); | ||
allProblemAndChildProblemIds.addAll(childProblemIds); // 문제 + 자식 문제 ID 합침 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문항과 새끼문항의 아이디를 set으로 합치는 이유는 어떤걸가요? |
||
|
||
// 문항 및 자식 문항의 개념 태그 조회 | ||
Map<Long, Set<String>> conceptTagMap = queryFactory | ||
.select(problem.id, conceptTag.name) | ||
.from(problem) | ||
.leftJoin(conceptTag) | ||
.on(conceptTag.id.in(problem.conceptTagIds)) | ||
.where(problem.id.in(allProblemAndChildProblemIds)) // 문제 + 자식 문제 ID | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 문항 테이블에서 새끼 문항 id로 검색하는것 같은데요? |
||
.fetch() | ||
.stream() | ||
.collect( | ||
HashMap::new, | ||
(map, tuple) -> map | ||
.computeIfAbsent(tuple.get(problem.id), k -> new HashSet<>()) | ||
.add(tuple.get(conceptTag.name)), | ||
HashMap::putAll | ||
); | ||
|
||
List<ProblemSummaryResponse> problemSummaries = problemData.stream() | ||
.map(tuple -> ProblemSummaryResponse.builder() | ||
.problemId(tuple.get(problem.id)) | ||
.problemCustomId(tuple.get(problem.problemCustomId.id)) | ||
.problemTitle(tuple.get(problem.title.title)) | ||
.memo(tuple.get(problem.memo)) | ||
.mainProblemImageUrl(tuple.get(problem.mainProblemImageUrl)) | ||
.tagNames(conceptTagMap.getOrDefault(tuple.get(problem.id), new HashSet<>())) // 태그 매핑 | ||
.build() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. DTO에 대한 정보가 repository까지 내려오는거는 유지보수 관점에서 좋지 않은것 같아요 |
||
) | ||
.toList(); | ||
|
||
return ProblemSetGetResponse.of(problemSet, publishedDates, problemSummaries); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,22 +1,11 @@ | ||
package com.moplus.moplus_server.domain.problemset.service; | ||
|
||
import com.moplus.moplus_server.domain.concept.domain.ConceptTag; | ||
import com.moplus.moplus_server.domain.concept.repository.ConceptTagRepository; | ||
import com.moplus.moplus_server.domain.problem.domain.problem.Problem; | ||
import com.moplus.moplus_server.domain.problem.repository.ProblemRepository; | ||
import com.moplus.moplus_server.domain.problemset.domain.ProblemSet; | ||
import com.moplus.moplus_server.admin.problemset.dto.response.ProblemSetGetResponse; | ||
import com.moplus.moplus_server.admin.problemset.dto.response.ProblemSummaryResponse; | ||
import com.moplus.moplus_server.domain.problemset.repository.ProblemSetGetRepositoryCustom; | ||
import com.moplus.moplus_server.domain.problemset.repository.ProblemSetRepository; | ||
import com.moplus.moplus_server.admin.publish.domain.Publish; | ||
import com.moplus.moplus_server.domain.publish.repository.PublishRepository; | ||
import com.moplus.moplus_server.global.error.exception.BusinessException; | ||
import com.moplus.moplus_server.global.error.exception.ErrorCode; | ||
import java.time.LocalDate; | ||
import java.util.ArrayList; | ||
import java.util.HashSet; | ||
import java.util.List; | ||
import java.util.Set; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
@@ -26,33 +15,14 @@ | |
public class ProblemSetGetService { | ||
|
||
private final ProblemSetRepository problemSetRepository; | ||
private final ProblemRepository problemRepository; | ||
private final ConceptTagRepository conceptTagRepository; | ||
private final PublishRepository publishRepository; | ||
private final ProblemSetGetRepositoryCustom problemSetGetRepositoryCustom; | ||
|
||
@Transactional(readOnly = true) | ||
public ProblemSetGetResponse getProblemSet(Long problemSetId) { | ||
ProblemSet problemSet = problemSetRepository.findByIdElseThrow(problemSetId); | ||
if (problemSet.isDeleted()) { | ||
throw new BusinessException(ErrorCode.DELETE_PROBLEM_SET_GET_ERROR); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 명시적인 예외 클래스로 만들어주실 수 있을까요? |
||
} | ||
List<LocalDate> publishedDates = publishRepository.findByProblemSetId(problemSetId).stream() | ||
.map(Publish::getPublishedDate) | ||
.toList(); | ||
|
||
List<ProblemSummaryResponse> problemSummaries = new ArrayList<>(); | ||
for (Long problemId : problemSet.getProblemIds()) { | ||
Problem problem = problemRepository.findByIdElseThrow(problemId); | ||
Set<String> tagNames = new HashSet<>( | ||
conceptTagRepository.findAllByIdsElseThrow(problem.getConceptTagIds()) | ||
.stream() | ||
.map(ConceptTag::getName) | ||
.toList()); | ||
problem.getChildProblems().stream() | ||
.map(childProblem -> conceptTagRepository.findAllByIdsElseThrow(childProblem.getConceptTagIds())) | ||
.forEach(conceptTags -> tagNames.addAll(conceptTags.stream().map(ConceptTag::getName).toList())); | ||
problemSummaries.add(ProblemSummaryResponse.of(problem, tagNames)); | ||
} | ||
return ProblemSetGetResponse.of(problemSet, publishedDates, problemSummaries); | ||
return problemSetGetRepositoryCustom.getProblemSet(problemSet); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JPA는 select 문에 조회하고 싶은 엔티티를 넣어야지 영속성 컨텍스트에 반영해요
fetch join을 해서 영속성 컨텍스트에 넣어주거나 select 문에 엔티티를 선언해주어야해요