221113 TIL 댓글을 삭제했는데 대댓글은 왜?

댓글 삭제 기능 구현 중 대댓글과 관련된 이슈가 발생했다.

대댓글이 있는 댓글을 삭제하면 밑에 달려있던 대댓글까지 1+1 마냥 같이 삭제가 돼버리는 문제 발생한 것이다. 근데 데이터베이스를 확인해보니 댓글은 지워졌지만 대댓글은 지워지지 않았었다. 사실은 대댓글은 삭제가 된 것이 아니라 화면에 보이지 않는 것이었다.

왜냐하면 댓글이 있어야만 해당 댓글 밑에 대댓글이 보이게 해 놨기 때문이다. 댓글이 없어져 버리면 대댓글도 같이 없어져 버리는 기이한 현상이... 

 

그래서 댓글을 삭제할 때 대댓글을 어떻게 처리해줄까 방법을 고민해봤다.

처음으로 생각해낸 방법은 댓글 삭제 시 대댓글이 있으면 대댓글이 존재하기 때문에 댓글을 삭제할 수 없다는 문구가 나오게 하는 것이었다.

 

두 번째 방법은 대댓글이 있는 경우에도 댓글을 삭제할 수 있지만 해당 댓글은 정말로 데이터 베이스에서 삭제된 것이 아니라 댓글의 삭제 유무 상태 값을 변경해 삭제된 상태이면 "삭제된 댓글입니다"라는 문구가 표시되도록 처리하고 대댓글이 전부 지워질 시에 해당 댓글은 완전히 삭제되는 방법이었다.

결론적으로 두 번째 방법을 선택했다. 첫번째 방법을 선택하지 않은 이유는 다른 사용자가 대댓글을 지우지 않으면 영원히 댓글을 삭제할 수 없기 때문에 선택하지 않았다.

 

두 번째 방법을 처리하려고 하니 생각보다 로직이 복잡해져야 했다.

게시글 삭제 기능은 단순 repository에서 delete만 했던 것에 비해 댓글 삭제 기능은 조건문을 이용해 검사해줘야 하는 부분이 있어 더 복잡해졌다.

 

우선 댓글을 삭제할때 해당 댓글에 대댓글이 있는지 없는지부터 검사해야 했다.

해당 조건을 검사할 때 jpa repository에 아주 적합한 메서드가 있다는 것을 알게 되었다.

existsById

주어진 id값을 가진 엔티티가 존재하는지 안 하는지 boolean 타입으로 알려주는 메서드이다.

 

existsById 메서드를 이용해 대댓글 저장소에 삭제하려는 댓글의 아이디를 갖고 있는 대댓글이 있는지 없는지 찾을 수 있었다.

대댓글 엔티티에 댓글의 아이디를 갖고 있기 때문에 대댓글 레파지토리에서 주어진 댓글의 아이디를 갖고 있으면 대댓글이 있다는 이야기니까 댓글을 완전히 삭제하는 것이 아니라 상태 값만 변경해서 "삭제된 댓글입니다" 표시가 나오게 했다. 

if(recommentRepository.existsByCommentId(commentId)) {
      댓글의 삭제 상태를 true로 변경
}

 

 

대댓글 레파지토리에 댓글이 없으면 해당 댓글을 db에서 완전히 지워버렸다.

위와 같이 구현하면 아래와 같은 결과물이 나온다. 

 

 

1번째 댓글에 대댓글이 존재하기 때문에 해당 댓글을 지워도 "삭제된 댓글입니다"라고 표시가 된다. 하지만 아직 해당 댓글은 db에서 지워진 게 아니라서 전체 게시물을 볼 때 제목 옆에 있는 댓글의 수가 2개로 나타난다. (손흥민 득점왕 수상 [2] -> 댓글 수)

 

해당 문제는 댓글의 deleted  상태가 true이면 카운트하지 않게 바꿔줘서 금방 해결할 수 있었다.

 

그리고 마지막으로 대댓글이 다 지워지면 삭제된 댓글이라고 나온 댓글도 db에서 같이 제거해주는 작업이 필요했다.

 

대댓글 삭제 로직 순서

1. 우선 지우려는 대댓글의 아이디를 백엔드에 전달해준다.

2. 해당 아이디 값으로 대댓글 레파지토리에서 대댓글 엔티티를 찾아온다.

Recomment recomment = recommentRepository.getReferenceById(recommentId);

여기서 getReferenceById를 사용한 이유는 대댓글 저장소에 무조건 대댓글이 존재하기 때문에(이미 존재하는 대댓글을 지우려고 하기 때문에) findById가 아닌 getReferenceById를 사용

 

if(commentRepository.getReferenceById(recomment.commentId()).isDeleted()) {       
     Comment comment = commentRepository.getReferenceById(recomment.commentId());

     recommentRepository.delete(recomment);

     if(!recommentRepository.existsByCommentId(comment.id())) {
            commentRepository.delete(comment);
     }
}

3. 댓글 레파지토리에서 대댓글이 갖고 있는 댓글의 아이디로 댓글을 찾은 다음 댓글의 삭제 상태를 검사한다.

4. 댓글 삭제 상태가 true일시 일단 지우려는 대댓글은 db에서 제거하고 해당 댓글을 가져온다.

5. 그리고 해당 댓글에 대댓글이 또 있는지 검사를 한다.

처음에 이 작업을 해주지 않아서 댓글에 대댓글이 여러 개가 있을 때도 대댓글 하나만 지워도 댓글이 삭제돼버리는 문제가 발생했다.

그래서 만일 댓글에 대댓글이 여러 개 있으면 지우려는 대댓글만 지우고 종료하고 다른 대댓글이 없으면 대댓글도 지우고 댓글도 지워서 모두 제거한다.

 

if(!commentRepository.getReferenceById(recomment.commentId()).isDeleted()) {
      recommentRepository.delete(recomment);
}

6. 다시 3번으로 돌아가 만일 댓글의 삭제 상태가 false면 댓글이 지워져있지 않다는 소리이니까 지우려는 대댓글만 지운다.

 

오늘은 삭제된 댓글을 어떻게 처리해줄까에 대한 고민과 댓글을 삭제하는 로직을 더 간단한 방법이나 더 좋은 방법이 없을까에 대한 고민을 많이 했던 것 같다. 이전에는 그냥 구현이 되는대로 코드를 치는 경우가 꽤 있었는데 이번 주부터는 생각을 한번 더 하고 더 나은 방법을 고민하고 코드를 작성해보자!