[01.11] 내일배움캠프[Spring] TIL-51
1. SQL
Join
SELECT *
from buy b join member m on b.mem_id = m.mem_id;
SELECT *
from buy b join member m on b.mem_id = m.mem_id
where b.mem_id = "BLK";
select m.mem_id,m.mem_name,b.prod_name,m.addr
from member m LEFT OUTER JOIN buy b
ON m.mem_id = b.mem_id
ORDER BY m.mem_id;
2. 기존 프로젝트 리펙토링
CASCADE( 유저탈퇴 )
- 원래는 엔티티별로 연관관계를 설정해줬었는데, 연관관계를 끊어주고 ID의 속성만 들고 있게하여
CASCADE
속성을 쓰지 못하게 됐다.
- 그래서
UserId
를 바탕으로 해당 유저가 쓴 게시글, 댓글을 지워주는 방향으로 코드를 작성했다.
UserService
@Transactional
public String delete(User user) {
String userName = user.getUsername();
userRepository.deleteById(user.getId());
boardService.deleteAllBoardByUser(user.getId());
commentService.deleteCommentByUser(user.getId());
return userName+"님이 탈퇴 되셨습니다, 관련 정보는 모두 사라집니다!";
}
- UserService라는 비즈니스 로직에 BoardService, CommentService가 DI되어있는게 걸리지만, 현재로써는 이게 최선이다.
대댓글( 연관관계 설정 )
- 원래 추상적으로 생각했을 때는
게시글 -> 댓글
처럼 대댓글 엔티티를 따로 만들어주려고 했었다.
- 그렇게 했을 때 뭔가 관리해야할 테이블도 하나 더 생기는 기분이라 기존에 있던
Comment
를 활용하면 어떨가 하는 생각이 들었고, 어차피 댓글의 속성을 그대로 가져가니, 그래도 될거라는 생각으로 구글링에 들어갔다.
- 구글링 결과 대부분 계층형 구조로 연관관계를 지어서 사용하고 있었고, 그 생각을 바탕으로 코드를 작성했다.
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "PARENT_ID")
private Comment parent;
@OneToMany(mappedBy = "parent",cascade = CascadeType.ALL)
private List<Comment> child = new ArrayList<>();
- 처음에 왜
@ManyToOne
으로 Comment 타입으로 parent를 선언했을까를 먼저 고민했다.
- 댓글 < - > 대댓글은 일단 1:N의 관계이다. 그런데 대댓글의 엔티티 입장으로 봤을 때는 댓글과
@ManyToOne
이 된다. 따라서 Parent(원래 댓글)과 대댓글의 관계 = @ManyToOne이 되는게 맞다.
@OneToMany
로 양방향은 왜 맺어준 것일까?
- 지난 번
Board
< - > Comment
를 양방향 맺어준 것 처럼 Board에서 해당 댓글을 모두 가져올 때 편하게 사용하기 위함( 객체 지향적 )이 아닐까 생각은 들지만, 이 때 N+1
의 문제가 발생할 수 있다.
- 만약 대댓글이 1만개인데, comment.getChild()를 하면?? 쿼리 1만1개 다 나가게 되기 때문에!
간단한 에로사항 및 해결
Board.getComment()
를 사용해서 DTO로 반환했을 때는 Comment가 없어도 NPE
가 발생하지 않았지만,
위와 같은 상황에서는 comment.getChild()
를 했을 때는 NPE
가 발생했다.
- 생각해보면 간단했다. -> Board는 게시글이 생성되어 있으므로 Board Entity가 잘 돌아갔고,
Board.getComment()
가 []로 초기화가 되어 들어갈 수 있기 때문이다.
- Comment는 Comment가 만들어지지도 않았는데 comment.get~~~를 한다? 모순이다.
package com.sparta.spartagroupsixproject.dto;
import com.sparta.spartagroupsixproject.entity.Comment;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Getter
public class CommentResponseDto {
private Long id;
private String content;
private LocalDateTime createdAt;
private LocalDateTime modifiedAt;
private Long likenum;
private List<CommentResponseDto> children = new ArrayList<>();
public CommentResponseDto(Comment comment){
this.id = comment.getId();
this.content = comment.getContent();
this.likenum = comment.getLikenum();
this.createdAt =comment.getCreatedAt();
this.modifiedAt = comment.getModifiedAt();
if(comment.getChild()!=null) {
for (Comment comment1 : comment.getChild()) {
children.add(new CommentResponseDto(comment1));
}
}
}
}
- 그래서 일단 null이 아닐 때 comment.getChild()를 할 수 있도록 조건을 걸어서 해결했다.
- 내일은 양방향 연관관계를 끊고 ID값으로만 작업을 해볼 예정이다 ( N+1 )
3. 코딩 테스트