책을 읽고 배운 내용을 정리한다.
MappedBy
- 양방향 바인딩에 있어서 생각할 점은 어느 쪽에 MappedBy를 사용할 것이냐이다.
- MappedBy는 주인이 아닌 엔티티의 변수에 할당해줘야 한다.
- 주인이 아니라는 것은 DB 테이블로 생각했을 때 해당 엔티티와 맵핑되어있는 테이블에서 FK를 관리하지 않는다는 것과 같다.
- 예를 들어 회원, 팀이 있으면 회원 엔티티에는 Team team이, 팀 엔티티에는 List <Member> members가 있을 것이다.
- DB 테이블로 상상해서 생각해보면 JOIN을 고려했을 때 테이블 모델링을 하면 TEAM_ID라는 FK는 멤버 테이블에 있는 게 일반적으로 생각할 수 있는 모습이다.
- 그래서 일반적으로 @ManyToOne을 가지고 있는 엔티티는 항상 연관관계의 주인이 된다. 항상 많은 쪽이 왜래 키를 가지기 때문이다.
- 헷갈릴 땐 DB 테이블이 어떻게 될지를 상상해보고, FK를 가지고 있는 테이블이 주인이고, 그렇지 않은 테이블의 객체 맵핑 변수에 MappedBy를 사용해준다고 생각하자.
순수한 객체까지 고려한 양방향 연관관계
- 객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다.
- 예를 들면 팀 엔티티에도 회원을 추가해주고, 회원 엔티티에도 팀을 설정해주는 것이다.
- 객체와 RDB까지 같이 고려하려면 이 두 가지를 동시에 해줘야 한다.
- 반드시 주인인 쪽에 (FK를 가지고 있는 테이블에 대한 엔티티)에 객체를 할당해주고, 반대쪽에도 해당 객체를 할당해주자.
- 그렇기 때문에 관계를 만들 때는 두 가지를 동시에 해줄 수 있도록 메서드로 따로 빼서 문제가 발생하지 않도록 하는 것이 바람직하다.
public class Member{
private Team team;
public void setTeam(Team team){
this.team = team;
team.getMembers().add(this);
}
}
- 위 코드는 연관 관계를 끊을 때 OneToMany 쪽에서도 객체를 제거해줘야 하는 부분이 없기 때문에 올바르게 작동하지 않는다.
public class Member{
private Team team;
public void setTeam(Team team){
if(this.team != null){
this.team.getMembers().remove(this);
}
this.team = team;
team.getMembers().add(this);
}
}
- 이렇게 수정해서 기존 관계를 제거하도록 한다.
- 사실 이렇게 하지 않아도 데이터베이스의 기록을 보면 아무런 문제가 없어 보인다.
- 실제로 Team 테이블은 Member 테이블의 정보를 가지고 있지 않기 때문이다.
- 하지만 이런 작업을 한 Team 객체가 영속성 콘텍스트에 남아있는 상태에서 다시 사용한다면, 관계를 끊어서 없어야 하는 Member를 조회할 수 있는 오류가 발생한다.
- 즉 객체를 관리하는 것은 굉장히 많은 것을 고려해야 한다. JPA는 이런 것을 신경 쓰지 않고 개발자가 비즈니스 로직 구현에 집중할 수 있게 한다.
매핑 요약
- 단방향 매핑만으로 테이블, 객체의 연관관계 매핑은 이미 완료되었다.
- 단방향을 양방향으로 만들면 반대방향으로 객체 그래프 탐색 기능이 추가된다.(그뿐이다)
- 양방향 연관 관계를 매핑하려면 객체에서 양쪽 방향을 모두 관리해야 한다.
- 연관관계의 주인은 외래 키의 위치와 관련해서 정해야 한다. 비즈니스 적인 중요도로 접근하면 안 된다.
'Programming' 카테고리의 다른 글
Flask 사용법 (2) | 2021.05.17 |
---|---|
JPA Study 03 (0) | 2021.05.16 |
JPA Study 01 (0) | 2021.05.15 |
DB 예약어(MySQL, MariaDB) (0) | 2021.05.14 |
Spring Study 04 (0) | 2021.05.05 |