[TIL] 20241011 주특기 플러스 개인과제 트러블 슈팅

ekkkyo_j·2024년 10월 11일

[내배캠 Java 6기] TIL

목록 보기
32/38

https://github.com/ekj1003/spring-plus

트러블 슈팅

제목의 keyword, 할일의 createdAt, 담당자의 nickname으로 일정을 검색하는 기능을 구현하는데 몇가지 문제가 발생했다.

1. 조인 방식 문제

발단

Todo는 Todo의 댓글인 comments와 담당자인 managers와 연관관계가 존재한다. TodoQueryRepositoryImpl.java에서 todo를 가져오기 위해, comment와 manager 테이블과 join하여 코드를 작성했다.

문제 발생

http://localhost:8080/todos/search/projections?createdAt=2024-10-10&nickname=imadmin

이런 식으로 GET 요청을 보냈는데, contents에는 아무것도 들어있지 않은 빈 리스트만 있었다. 즉, 요청에 해당하는 todo가 걸러지지 않았다.

원인

join은 manager, comment가 없는 todo의 경우 조회되지 않는다는 것을 깨달았다.

해결방안

comment와 manager 테이블과의 조인 방식을 그냥 join이 아니라 leftJoin으로 불러와야한다.

leftJoin은 주 테이블(여기서는 todo)과 관련된 다른 테이블(managers, comments, user) 간의 관계에서 모든 주 테이블의 데이터를 가져오고, 관련된 데이터가 없으면 NULL로 처리하는 조인 방식이다.

이 방식을 사용하는 이유는, 일정(todo)이 존재하지만 해당 일정에 관련된 담당자(manager) 또는 댓글(comment) 이 없을 수도 있기 때문이다. leftJoin을 사용하면, 이런 경우에도 일정을 포함해 모든 결과를 가져올 수 있다.

TodoQueryRepositoryImpl.java

@Override
    public Page<TodoProjectionDto> searchTodos(Pageable pageable, String keyword, LocalDate createdAt, String nickname) {
        List<TodoProjectionDto> todos = queryFactory
                .select(Projections.constructor(TodoProjectionDto.class,
                        todo.title,
                        manager.countDistinct().as("managerCount"),
                        comment.countDistinct().as("commentCount")
                ))
                .from(todo)
                .leftJoin(todo.managers, manager)
                .leftJoin(manager.user, user)
                .leftJoin(todo.comments, comment)
                .where(
                        allConditions(keyword, createdAt, nickname)
                )
                .groupBy(todo.id)
                .orderBy(todo.createdAt.desc())
                .offset(pageable.getOffset())
                .limit(pageable.getPageSize())
                .fetch();

        Long total = queryFactory
                .select(Wildcard.count)
                .from(todo)
                .leftJoin(todo.managers, manager)
                .leftJoin(manager.user, user)
                .where(
                        allConditions(keyword, createdAt, nickname)
                )
                .fetchOne();

        return new PageImpl<>(todos, pageable, total);
    }

2. 담당자의 닉네임 불러오기

발단

담당자는 todo에 여러명 배치될수 있는데, nickname을 요청으로 보내면 해당 nickname을 포함한 담당자가 배치된 todo를 불러와야한다. 하지만, 403 Forbidden 에러가 발생하였다.

해결방안

           .leftJoin(todo.managers, manager)
                .leftJoin(manager.user, user)
                .leftJoin(todo.comments, comment)

manager.user까지 leftJoin을 한다.
manager와 연관된 사용자(user)의 닉네임으로도 검색을 가능하게 하기 위해서이다.

Todo는 여러 Manager와 연결되어 있고, 각 Manager는 사용자(User) 정보도 가지고 있다. 닉네임으로 검색할 때, 사용자의 닉네임을 통해서 일정(todo)을 필터링하기 위해 manager.user.nickname이 필요하다.

profile
게으르지만 성실히 공부하기^_^

0개의 댓글