사용자가 참여하고 있는 그룹의 목록을 조회할 떄
// GroupServiceImpl.java
public List<MyGroupResponseDto> getMyGroupsByLeader(Long userId) {
List<Group> groups = groupRepository.findAllByUserIdOrderByCreatedAtDesc(userId);
List<MyGroupResponseDto> myGroupResponseDtoList = new ArrayList<>();
for (Group group : groups) {
List<Participant> participants = participantRepository.findAllByGroupIdOrderByCreatedAtDesc(
group.getId());
List<ParticipantResponseDto> participantResponseDtoList = new ArrayList<>();
for (Participant participant : participants) {
participantResponseDtoList.add(new ParticipantResponseDto(participant));
}
myGroupResponseDtoList.add(new MyGroupResponseDto(group, participantResponseDtoList));
}
return myGroupResponseDtoList;
}
처음에 작성을 하고 이중 for문에 집중에서 수정으로 하려고 했는데 정작 문제는 다른 데 있었다. for문 안에서 repository를 조회하면 for문을 한 번 돌 때마다 쿼리가 계속 날라가게 되므로 서버가 터질 수 있는 문제점이 있다. 그래서 jpql로 그룹 id와 연결된 참여자의 리스트를 찾는 쿼리를 짜고 그걸 이용해서 수정을 했다. 페치 조인을 사용하면 연관된 엔티티를 한 번의 쿼리로 모두 가져올 수 있다. 그리고 쿼리가 n+1로 날라갈 수 있는걸 해결한다.
쿼리를 직접 짜서 for문에서 뺄 수 있고 훨씬 적은 수의 쿼리로 조회할 수 있게 되었다.
// ParticipantRepository.java
public interface ParticipantRepository extends JpaRepository<Participant, Long> {
@Query(value = "select p from Participant p join fetch p.group where p.group.id in (:groupIdList)")
List<Participant> findAllParticipants(@Param("groupIdList") List<Long> groupIdList);
}
// GroupServiceImpl.java
public List<MyGroupResponseDto> getMyGroupsByLeader(Long userId) {
List<MyGroupResponseDto> myGroupResponseDtoList = new ArrayList<>();
List<Group> groups = groupRepository.findAllByUserIdOrderByCreatedAtDesc(userId);
List<Long> groupIdList = groups
.stream()
.map(Group::getId)
.toList();
List<Participant> participants = participantRepository.findAllParticipants(groupIdList);
for (Group group : groups) {
List<ParticipantResponseDto> participantResponseDtoList = participants.stream()
.filter(p -> p.getGroup().getId().equals(group.getId()))
.map(Participant::toParticipantResponseDto)
.toList();
myGroupResponseDtoList.add(new MyGroupResponseDto(group, participantResponseDtoList));
}
return myGroupResponseDtoList;
}
처음에 로직을 구성할 때 쿼리가 얼마나 날라가는지에 대한 생각도 필요한 것 같다. 그걸 모두 고려해서 작성해야한다. jpa공부가 더 필요하다. 다른분들의 도움을 받아 작성했지만 아직 스트림에 대한 개념도 부족하기 떄문에 갈 길이 멀다..
위에서 쓴 스트림을 for문으로 바꿔보았당
List<ParticipantResponseDto> dtoList = new ArrayList<>();
for (Participant p : participants) {
if (p.getGroupId().equals(group.getId()) {
dtoList.add(new ParticipantResponseDto(p));
}
}