회고를 lv1부터 lv5까지 구현하고 나서 한번에 쓰는거라 순서가 뒤죽박죽이다.

  1. 댓글 조회할 때 그냥 return 했더니 scheduleId가 존재하지 않아도 빈배열로 리턴이 됨 → 에러가 떨어지지 않음 왜?

    List<Comment> findByScheduleIdOrderByCreatedAtDesc(Long scheduleId);
    

    이 메서드 호출 했을 때 scheduleId를 참조하는 댓글이 없다면 빈 리스트 반환이 기본 동작이라고 한다. 이 쿼리는 단순히 조건을 만족하는 comments를 찾는 쿼리기 때문에 댓글이 없는 거와 일정이 없는 것을 구분한다. 그래서 만약 존재하지 않는 글의 댓글을 조회했을 때 에러를 떨구고 싶다면 일정이 있는지 없는지를 체크해 주면 된다.

    그래서 나는 댓글 조회에 scheduleService.findScheduleOrThrow(scheduleId); 이걸 추가해 줬다!

  2. repository에서 jpa를 extends 받았기 때문에 기본 제공되는 기능을 사용할 수 있는 거까지는 이해 완료. 간단한 것들은 다 있는 것 같았다. 근데 findByScheduleIdOrderByCreatedAtDesc 이거나 countByScheduleId 이런 식으로 여러 개 넣어서 쓰는 게 작동이 된다는 게 너무 신기함.

    → 직접 구현하지 않아도 사용할 수 있는 이유는 Spring Data JAP는 메서드 이름 기반 쿼리 생성 기능이 있음. 그래서 중요한 게 메서드 이름으로 쿼리르 만드는 것임!!!

    Long countByScheduleId(Long scheduleId);
    
    SELECT COUNT(*) FROM comment WHERE schedule_id = ?
    

    이렇게 자동 생성해 주는데… 그래서 궁금했던 게 그러면

    countCommentsByScheduleId는 동작하는가 이름이 이렇게 직관적인데! 삐빕 동작하지 않는다. comments를 쓰면 comments라는 필드가 있다고 잘못 해석하다고 한다ㅠ… 내 Comment 안엔 그런 필드가 없거든…!!

    그럼 countByScheduleId 이건 왜 동작하냐면 Comment 엔티티 안에 schedule이 있기 때문이다. 그래서 schedule.id를 통해 scheduleId로 파싱 가능한 것이다.

    만약 countCommentsByScheduleId 이걸 쓰고 싶다면 직접 쿼리를 작성해야 한다고 해서 Spring JPA 규칙에 맞는 메서드명으로 사용하는 것이 편하고 좋다.

  3. Sort처리하는 것과 findByWriterOrderByUpdatedAtDesc 쓰는것…

    if (writer == null || writer.isEmpty()) {
        schedules = scheduleRepository.findAll(Sort.by(Sort.Direction.DESC, "updatedAt"));
    } else {
        schedules = scheduleRepository.findByWriterOrderByUpdatedAtDesc(writer);
    }
    

    writer가 주어지면 → 특정 작성자 일정만 조회 (수정일 순)

    writer가 없으면 → 전체 일정 조회 (수정일 순)

    이런 방법도 있고 저런 방법도 있고~

  4. Comment entity에서 다른 entity를 불러와서 사용하려 하니까 빨간 줄

    그래서 인텔리제이가 제안하는 걸 눌렀더니 @ManyToOne@JoinColumn이라는 게 붙여졌다. 영어로만 본다면 다대일과 컬럼 조인해주는 것 같은데 SQL로 처리하는 걸 이렇게 어노테이션을 사용해서 구현하는건가? 싶었다

    @ManyToOne@JoinColumn은 SQL의 JOIN문과 직접적으로 같지는 않다고 한다. 하지만 DB 테이블 간 관계를 정의하고 JPA가 내부적으로 쿼리를 생성해서 실행하게 되는 것!!… 대충 비슷하다고 보면 될듯??

    어쨌든 @JoinColumn 덕분에 각 댓글에 일정 아이디가 들어가서 어느 일정에 속하는지 연결해주는 것이다!!

  5. nullable = false? 없는 값을 막아주는 건가 null만 막아주는건가?

    이건 1번거랑 이어진다고 보는데 저건 DB 레벨에서의 null 허용 여부를 설정하는거지 존재하지 않는 스케줄id를 막아주는 것은 절대 아니다.

    just 스케줄이 null이면 DB에 저장이 안 되는 것만 보장. 그래서 서비스에서 일정 있는지 없는지 체크하는 로직을 넣어줘야만 하는 것~

  6. 댓글 수정과 삭제 기능..

    이건 연습할 겸 추가로 수정과 삭제를 만들어봤는데 수정과 삭제를 할 때는 꼭 scheduleId가 필요하지 않은 것 같다고 느꼈다… 근데 Restful하게 짜려면 넣어야할 것 같기도 하고… 근데 그러면 필요도 없는 schedulId를 다 받아놔야 하기 때문에 뭔가 의미없는 일을 하는 것 같기도 해서 일단은! 바로 /comments/{id}로 해서 만들었다. 뭐가 더 알맞은 건지 모르겠다.

  7. 단건 조회에 댓글 추가하기

    말만 들으면 엄청 손쉽게 할 거라고 생각했는데 생각보다 난이도가 있었다

    일단 전체 조회할때는 나오지 않고 단건 조회할때만 나와야한다…? 여기부터 동공지진 그러면 dto를 수정하는 게 아니라 새로 만들어야 하네

    그럼 일단 DetailResponseDto를 따로 생성해줘야 하고 스케줄 엔티티에는 Comment list를 추가해줘야 한다.

     @OneToMany(mappedBy = "schedule")
        private List<Comment> comments = new ArrayList<>();
    

    처음엔 그냥 밑에거만 추가해서 했는데 빌드했더니 에러. JPA 어노테이션이 빠졌다는 뜻. 내가 dto에서 schedule.getComments를 했는데 그거때문에 안 되나보다 일단 댓글은 스케줄에 연결되서 저장되니까 이건 단방향 관계로 이어져 있는데 스케줄 기준에서 댓글을 조회하는 기능을 쓰려면 @OneToMany를 추가해서 스케줄 기준으로 연결된 댓글 목록을 가지고 올 수 있게 된다.

    나는 댓글을 그냥 스케줄의 findById로 불러와서 보여줬는데 @OneToMany 가 지연 로딩 방식이라고 한다. 즉시 로딩으로 바꿔주려면 @EntityGraph를 사용해서 그냥 넣어주기만 하면 되는 것 같다 (이론 모름)

    근데 찾아보니 일반적인 일반적으로 댓글은 사용자가 모든 댓글을 보지 않을 가능성이 높기 때문에 지연 로딩이 더 나은 선택일 수도 있다고 한다!

    댓글 수가 적거나 페이지 로딩 속도보다 데이터 접근 속도가 중요한 경우엔 즉시 로딩이 더 낫다고 한다. @OneToMany 찾아보다가 여기까지 와버렸다 여튼 지연로딩, 즉시로딩 그런 게 있나보다!

    제공된 강의 듣고 다른 반 강의도 다시보기로 도강하느라 과제 구현 시간이 너무 촉박했다… 일단 도전과제 Lv6까지 했고 Lv7은 나중에…

    1. 스웨거를 작성해 보려 했는데 Delete에 request Body가 들어가면 안 된다고 한다… 엥! 그래서 일단은 스웨거에서는 param으로 설정해 놓긴 했다. 근데 Param으로 하면 url에 비밀번호가 보여질 것이라 생각해서 body로 넣었다. 근데 스프링에서는 작동이 잘 됐었는데 스웨거만 안 되는건가 싶기도 하다.

      → 원래는 안 됐는데 최신에 되는 것 같음 Delete 매핑 대신 Post를 쓰고 url에 /delete 를 추가해서 구현했어도 됐을 것 같다

      → 어차피 나중엔 header를 쓰니까~