그렇다면 양방향 관계 해결 방법은??
Entity01 BookStore
@Entity
@Getter @Setter
public calss BookStore {
@Id @GenerateValue
private Integer id;
private String name;
@OneToMany(mappedBy ="bookStore")
private Set<book> books = new HashSet<>();
//add 메세지로 책을 책방에 추가한 것
void add(Book book){
book.setBookStore(this);
this.books.add(book);
}
}
book.setBookStore(this); 의 의미는 무엇일까?
book.setBookStore(this); 를 추가하고 실행시키면
데이터 베이스 결과는
book database
id isbn title book_store_id
16 | <null> | JPA 공부 좀 하면서 쓰자 | <null> |
22 | <null> | JPA 공부 좀 하면서 쓰자 | 21 |
book_store_id 에 null에서 아이디가 설정된걸 확인할 수 있다.
book_store database
id name
25 | 소피책방 |
21 | 소피책방 |
책방도 두개가 생겼다.
근데 왜 생겼을까?
여기서 왜 생겼는지 이해하지 못했다면,
OneToMany와 mappedBy가 뭔지 모르는 것이다.
이 두개의 개념을 모르면 1탄에서 왜 에러가 나는지 찾을 수가 없을 것이다.
양방향 관계 해설
관계를 다시 처음부터 맺어보겠다.
북스토어에서도 북을 참조 북을 여러개 참조하여 OneToMany
북에서도 북스토어를 참조 ManyToOne
이 두개의 관계는 양방행 관계가 아닙니다.
이 두개는 서로 다른 두개의 단방향 관계입니다.
Entity01 BookStore
OneToMany컬렉션을 bookStore에서 book을 참조하는 또 다른 단방향관계 이다.
@Entity
@Getter @Setter
public calss BookStore {
@Id @GenerateValue
private Integer id;
private String name;
@OneToMany
private Set<book> books = new HashSet<>();
//add 메세지로 책을 책방에 추가한 것
void add(Book book){
this.books.add(book);
}
}
Entity02 Book
이 관계는 book→ bookStore를 ManyToOne으로 보는 단방향 관계
@Entity
@Getter @Setter
public calss Book {
@Id @GenerateValue
private Integer id;
private String isbn;
private String title;
@ManytoOne
private BookStore;
}
이렇게 설정했을 때에는 스키마가 완전히 다르다.
테스트르 실행하면
@ManytoOne
private BookStore;
이 BookStore에 대해 해당하는 컬럼이 book이라는 테이블에
bookStore_id로 들어있다.
bookStore에서 book을 여러개 참조한
이관계는 기본적으로 조인테이블이 생성된다.
books_id와 bookStore_id가 조인된 테이블 생성된다.
이것이 기본 설정이다.
이게 hibernate jpa기본 Mapping방법이다.
OneToMany!
그런데 1편에서는
@OneToMany(mappedBy ="bookStore")
bookStore로 매핑이 되어있었다.
이걸함으로서 양방관계가 된거다.
그래도 주의할게 있다.
반드시 양방향 관게는 MappedBy로만 연결해야할까?
그렇지않다.
여러가지방법이 있는데, 이 두개의 OneToMany와 ManyToOne이 하나로 묶는 방법은
묶는 방법 중 하나가 지금 MappedBy를 사용해서 Entity02 book를 이 관계의 주인으로
설정하는 것이다. 1편처럼 mappedBy를 사용해서 스키마를 다시 만들면
테이블이 조인이 되지않고 2개만 나오게된다. Entity02 book쪽에서 외래키를 가지게 된다.
그래서 mappedBy의 의미는 관계의 주인을 나타내는 것이다.
이 관계의주인이 book이고, book에서 자기 자신을 bookStore이라고 참조하고 있다.
그러니까 Entity02 book이 주인이 되는 것이 무슨 뜻이지?
관계의 주인인 쪽에 관계가 설정해줘야한다.
그래야지만 데이터베이스에서 반영이 된다.
1편에서 작성한 그 코드들은 이상황에서 add를 할 때 어떻게 썻냐
.getBooks().add(book); 이렇게만 처리하였다.
이 관계의 주인은 book인데 book이 당하는 관계를 설정하지않고
현재 자기 자신한테만 관계를 설정하고 있는걸 알 수가 있다.
그러면 데이터베이스에 싱크를 할게 없는 것이다.
각기의 객체의 상태가 변경됐음에도 불구하고 데이터베이스에는 아무일도 일어나지않는다.
왜냐하면 관계의 주인이 book쪽의 아무런 변화가 일어나지않았기 떄문이다.
그래서 book쪽의 관계의 변경을 해줘야
book.setBookStore(this); 이렇게 !!
book에 이 관계의 주인의 book쪽에다가 bookStore를
설정을 해줘야하지만 db에 반영이 되는 것이다.
정답코드
Entity01 BookStore
@Entity
@Getter @Setter
public calss BookStore {
@Id @GenerateValue
private Integer id;
private String name;
@OneToMany(mappedBy ="bookStore")
private Set<book> books = new HashSet<>();
//add 메세지로 책을 책방에 추가한 것
public void add(Book book){
**book.setBookStore(this); //owner**
this.books.add(book); //그러면 이건 왜??
}
}
this.books.add(book); //그러면 이건 왜??
이런 질문은 왜 JPA를 쓰냐 ORM을 쓰냐하는 질문하고 똑같은 것
우리는 객체지향적이 코드라 데이터 베이스관계형 DB를 다루기 때문에
JPA를 쓰는 것이다.
객체지향적인 시각에서 바라봐도 당연히 이 관계를 맺을 때는
양방향 관계에서 둘다 설정이 되는 것이 맞다.
Entity02 Book
@Entity
@Getter @Setter
public calss Book {
@Id @GenerateValue
private Integer id;
private String isbn;
private String title;
@ManytoOne
private BookStore;
}
testCode
@RunWith(SpringRunner.class)
@SpringBootTest
public class DemoJpaTestApplicationTests{
@Autowired
BookStoreRepository bookStoreRepository;
@Autowired
BookRepository bookRepository;
@Test
public void contexLoads(){
//책방 보이죠?? 책방을 하나 만들고
bookStore bookStore = new BookStore();
bookStore.setName("소피 책방");
bookStoreRepository.save(bookStore);
//책을 만들었다.
Book book = new Book();
book.setTitle("JPA공부 좀 하면서 쓰자");
// 그 다음에 이 책을 책방에다가 추가했어요.
bookStore.add(book);
bookRepository.save(book);
}
}
'Back-end Skill > DataBase' 카테고리의 다른 글
[queryDsl] Q-type Class 는 도대체 왜 만드는건가? (0) | 2022.10.24 |
---|---|
[queryDsl] queryDsl에서 데이터 insert하는 방법 (0) | 2022.10.24 |
Python pandas을 통해 DB 마이그레이션하는 방법 (1) | 2022.10.05 |
SQL 예제를 통한 LEFT JOIN에 대해 알아보기 (0) | 2022.06.28 |
MySQL / MariaDB 페이지네이션 쿼리 작성하는 법 (0) | 2022.06.28 |