요약 : 무작정 Casacade.ALL로 설정하지 말고, 연관관계를 잘 살펴보자.
프로젝트를 거의 마무리 하던 도중, 댓글과 post의 매핑을 잘못하고 있었다는 충격적인 실수를 발견하고, 수정을 했다. Http Response로도 잘 넘어오는 것 까지 확인하고, 전체 테스트 코드를 돌려봤는데.... 댓글 delete 부분이 에러가 나는 것이었다..ㅠㅠ
대충 외래키 무결성이 안맞는다는 얘긴데... 보아 하니까 post에 포함된 comment들이 지워지지 않는 것이 문제였다..
지금 Comment Entity는 약간 복잡하게 섥혀있는 상태였다.
@Getter
...
@DiscriminatorValue("COMMENT")
public class Comment extends Component {
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "post_id")
private Post post;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "super_comment_id")
private Comment superComment;
@OneToMany(mappedBy = "superComment", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Comment> subComment = new ArrayList<>();
...
}
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@AllArgsConstructor
@DiscriminatorValue("POST")
public class Post extends Component {
private String title;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "channel_id")
private Channel channel;
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL,orphanRemoval = true)
private List<Image> images = new ArrayList<>();
@OneToMany(mappedBy = "post", cascade = CascadeType.ALL,orphanRemoval = true)
private List<Comment> commentList = new ArrayList<>();
....
}
나는 포스트와 댓글 둘다 Like를 가능하게 하고 싶었고, Post-Like,Comment-Like 의 관계를 따로 두고싶지 않아서, Post와 Like의 부모 클래스를 만들고 이를 상속받게 했다.
그 상태에서, Comment는 당연히 Post와 @ManyToOne의 관계를 맺고 있었고, 대댓글을 위한 Comment와 Comment의 Recursion한 @ManyToOne의 관계를 갖고 있었다.
그러다 보니까, 사실은 같은 부모 클래스를 두고 있는 아이들이 서로를 참조하고 있다보니, 이 부분에서 뭔가 문제가 있지 않을까 싶었다.
일단 쿼리를 살펴봤다.
보아하니, 포스트와 @OneToMany로 엮여있는 또다른 Image는 Delete 쿼리가 먼저 나간다.. Image가 CASACADE.ALL로 묶여있으니, 영속성 전이를 통해서 포스트가 삭제된다면 이미지 역시 삭제되어야 하니까 잘 나갔다.
하지만 Comment delete 쿼리가 나가지 않았다.
구글링을 해본 결과, 만약 다른 여러 엔티티와 연관관계를 맺고 있을 때, 영속성 전이가 잘못 된다면 삭제가 되지 않을 수도 있다는 것 같았다.. 그래서 아까 말한 것 처럼, 서로 재귀 참조 하는 과정에서 뭔가 문제가 있지 않을까 하고 열심히 삽질을 해봤는데 사실 문제는 다른데 있었으니...
문제는 그쪽이 아니라, Member와의 연관관계에 있었다. Comment와 Post는 Component를 상속받게 하였는데, Component는 멤버와 @ManyToOne으로 연관관계를 맺고 있었다.
어떻게 된 것인지 파악을 해보자면,
의 과정이 있었던 것 같다. 따라서, Member에서 Comment를 참조하는 부분을 CasacadeType.REMOVE로 바꾸니 테스트가 통과하였따..
만약 잘못 이해한 과정이 있으면 알려주세요..
Jpa를 배울 때 보통 CasacadeType.ALL로 배웠다 보니, 무의식적으로 그냥 죄다 이렇게 썼었는데, 연관관계를 잘 살펴보고 필요한 옵션을 골라야 할 것 같다.
팀원들과 논의와 실험 겨과, CasacadeType.REMOVAL이 없이 orpahnremoval=true 인 상태에서도 정상 작동하는 것을 확인했다. 물론 차이는 있지만, 원하는 기능에서는 문제가 없기 때문에 불필요한 코드로 판단, 아예 삭제하였다.