JPA의 Foreign Key적용 방식 및 원리
게시글과 댓글을 Spring으로 구현을 해야하는 상황에서 게시글과 댓글을 Foreign Key로 양방향 참조를 할 예정이다.
board 와 comments는 1:N 관계이다. 우선 Board에는 OneToMany를 Comments에는 ManyToOne을 설정해야한다는 것은 직관적으로 알 수 있다.
그렇다면 이 관계의 주인은 누구일까?
하나뿐인 Board가 주인일 것 같지만 아이러니 하게도 Comments가 주인이다.
Comments는 Board가 없으면 존재할 수 없지만 반대는 가능하기 때문에 외래키는 Comments쪽에서 관리하는 것이 타당하다.
주인 연관관계를 자세히 알았으니 코드에 적용시켜야 한다.
JPA에서는 mappedBy를 통해 양방향 관계를 설정한다.
mappedBy를 쓰기전 OneToMany와 ManyToOne이 적혀있다면 그것은 양방향관계라고 할 수 없고 단방향 관계가 2번 설정되었다고 할 수 있다.
mappedBy는 주인이 아닌 객체에 작성하며 의미는 다음과 같다.
주인은 Comments고 Comments에서 Borad를 참조하고 있다.
(Board객체에 작성했다는 점을 유의하자)
@OneToMany( mappedBy = "board")
private List<Comments> commentsList = new ArrayList<Comments>();
위 코드는 양방향 관계임을 명시하기만 했을 뿐이므로 실제로 두 객체를 연결시켜주는 함수를 만들어야 한다.
Comments가 생성되었을 때 Board를 꼭 참조하게 만들어야 한다. 그리고 Board또한 Comments를 참조해야한다.
public void addComments(Comments comments){
comments.setBoard(this);
this.commentsList.add(comments);
}
@PostMapping("/api/comments/{nid}")
public Comments createComments(@PathVariable Long nid, @RequestBody CommentsDto commentsDto){
Comments comments = new Comments(commentsDto);
Optional<Board> optionalBoard = boardRepository.findById(nid);
optionalBoard.ifPresent(board -> board.addComments(comments));
return commentsRepository.save(comments);
}
이런식으로 코드를 작성하게 되면 Repository에서 Response값을 return하게 되는데 두 객체가 서로를 참조하고 있기 때문에 stackoverflow 에러를 발생한다.
그래서 일단은 함수의 return형식을 void로 바꿔 주었지만 게시글이나 댓글의 목록을 보여주기 위해서는 해결해야만 하는 문제다.
추가) https://ojy9612.tistory.com/55 어노테이션으로 객체대신 아이디만 가져오게 했다.
결과 코드 요약
Board 객체
@Entity
public class Board ...{
...
@OneToMany( mappedBy = "board") // 주인은 Comment고 comment에서 borad를 참조하고 있다.
private List<Comments> commentsList = new ArrayList<Comments>();
public void addComments(Comments comments){
comments.setBoard(this);
this.commentsList.add(comments);
}
...
}
Comments 객체
@Entity
public class Comments ...{
...
@Setter
@ManyToOne
private Board board;
...
}
CommentController
@PostMapping("/api/comments/{nid}")
public void createComments(@PathVariable Long nid, @RequestBody CommentsDto commentsDto){
Comments comments = new Comments(commentsDto);
Optional<Board> optionalBoard = boardRepository.findById(nid);
optionalBoard.ifPresent(board -> board.addComments(comments));
commentsRepository.save(comments);
}
https://www.youtube.com/watch?v=brE0tYOV9jQ
https://www.youtube.com/watch?v=hsSc5epPXDs
'JAVA > Spring Boot' 카테고리의 다른 글
[Validation] 누락된 값 전역 처리, 클라이언트에 상세히 표시 (0) | 2023.01.25 |
---|---|
Spring Boot, Gradle 멀티 모듈 프로젝트 실전 예제 (0) | 2022.12.28 |
jwt 정리 잘 된 블로그 메모 (0) | 2022.07.13 |
JPA) N+1문제 (0) | 2022.06.20 |
JPA) 특정 컬럼 제외하고 반환하기 (0) | 2022.06.06 |