아래와 같이 두 클래스 Book, BookStore 가 있다.
둘을 연관관계 매핑을 했다고 생각했는데, 코드를 돌려보니 막상 DB에 정보가 반영되지 않는다. 왜 일까?
// Book.java
@Entity
@Getter @Setter
public class Book {
@Id
@GeneratedValue
private Long id;
private String isbn;
private String title;
@ManyToOne
private BookStore bookStore;
}
// BookStore.java
@Entity
@Getter @Setter
public class BookStore {
@Id
@GeneratedValue
private Long id;
private String name;
@OneToMany
private List<Book> books = new ArrayList<>();
public void add(Book book) {
this.books.add(book);
}
}
// contextLoad 코드
...
@Test
public void contextLoad() {
BookStore bookstore = new BookStore();
bookRepository.save(bookStore);
Book book = new Book();
bookStore.add(book);
bookRepository.save(book);
}
다행히 문제를 듣고 정답을 얘기할 수 있었다. 영상에서는 이것도 모르면 JPA 쓰지 말라고 하시던데..ㅎㅎ 다행이다.
우선 위 코드와 같이 작성을 하면 양방향 관계가 매핑된 것이 아니라 단방향 관계 2개가 세팅된 것이다.
여기에 추가로 BookStore 클래스에
@OneToMany(mappedBy = "bookStore")
private List<Book> books = new ArrayList<>();
를 적어주면 양방향으로 매핑되고, 연관관계의 주인을 Book으로 한다는 의미가 된다.
이 상태에서 실제로 add 메서드를 호출했을 때, 양방향 연관관계 매핑의 효과를 보기 위해서는 저렇게 BookStore 의 books에만 추가를 해주는 것이 아니라 Book에도 반영을 해줘야 한다.
즉, 아래 코드와 같이 연관 관계의 주인쪽에 데이터를 갱신해주고, 반대로 매핑되어 있는 객체에도 반영시켜 주는 작업이 필요하다.
public void add(Book book) {
book.setBookStore(this);
this.books.add(book);
}
더욱 더 근본적인 질문을 나에게 던지며 공부하는 습관을 기르자 라는 생각이 들었다.
- 나는
스프링을 왜 쓰는가?어떤 점이 좋아서쓰는가?- 나는
JPA를 왜 쓰는가?객체 지향적으로 DB를 다루면서 조심해야 하는 부분(이 영상에서 다룬 부분과 같이)은 뭘까?
앞으로도 항상 신경쓰며 개발 공부를 해 나갈 것이다.
영상 출처: 백기선님, JPA, OneToMany 양방향 관계 "MappedBy" 해설
https://www.youtube.com/watch?v=hsSc5epPXDs