DevKim
[JPA] 연관관계 매핑 - 단방향,양방향 연관관계 ,연관관계의 주인 본문
01. [ 객체 설계를 테이블 설계에 맞춘 방식의 경우 ]
다음과 같이 연관관계 매핑을 하지않고, Member가 외래키 값을 그대로 들고 있는 경우엔
member에서 외래 키 식별자를 직접 다루게 된다.
이렇게 되면, member를 저장할 때 다음과 같이 team에서 id를 받아와서, 그 id를 가지고 teamid를 설정해주어야한다.
이러한 방법은 전혀 객체지향스럽지 않고.. 바로 getTeam( )을 해야 속이 시원할 것 같은 느낌이다.
더불어, 조회시에도 이슈가 있다.
Team을 조회하기 위해선, member id로 원하는 member를 find하고,
찾은 member.getTeamId로 team의 id값 찾고..그 id값으로 다시 또 팀을 찾아줘야한다.
이렇게 되면 연관관계가 없으므로 계속 DB에 물어봐서 꺼내야한다.
전혀 객체지향스럽지 않은 방식이다.
즉,
객체를 테이블에 맞춰서 데이터 중심으로 모델링을 하면, 협력 공동체를 만들 수 없다.
(객체지향 설계의 목표는 자율적인 객체들의 협력 공동체를 만드는 것이다. 라고 책에서 말했다..)
이때, '테이블' 과 '객체'의 연관관계의 차이를 이해하는 것이 가장 중요하다고한다.
1. 테이블은 외래키로 'JOIN'을 사용해서 연관된 테이블을 찾는다.
2. 객체는 '참조'를 이용해서 연관된 객체를 찾는다.
[ 02. 단방향 연관관계 ]
위에서의 모델링을 객체 연관관계를 이용해서 다시 모델링하면 다음과 같다.
여러명의 member가 team에 들어갈 수 있으니, member와 team은 다:1 관계이다.
따라서 Member에서 Team과의 관계가 어떤 관계인지 매핑해주고,
이 관계를 할 때 Join하는 컬럼은 테이블 연관관계에서의 외래키이기 때문에 TEAM_ID와 매핑해주었다.
이렇게 연관관계를 매핑해주면, 회원 저장시 member.setTeam(team) 으로만 넣어주면
JPA가 알아서 team에서 PK값 꺼내서 FK insert 할 때, FK로 사용을 한다고한다.
조회시엔 get으로 바로 가져올 수 있고
수정시에도 member.setTeam(team)으로 수정 가능해진다.
실행해보면, select 쿼리가 안나가는데, 그건 영속성 컨텍스트의 1차 캐시에 저장되어 있는 것을 찾아서
반환했기 때문에 그렇다.
DB에서 가져오는 쿼리를 가져오고 싶으면,
em.flush( ) 후 em.clear( ) 를 해주어
플러쉬해주고 clear로 영속성 컨텍스트를 초기화해주면 된다.
[ 03. 양방향 연관관계 ]
단방향 연관관계와 양방향 연관관계에서의 테이블 연관관계는 변화가 없다.
왜?
Member에서 소속된 Team을 알고 싶거나, Team에서 소속한 Member을 알고 싶을 땐
양쪽의 TEAM_ID 두개를 join하면 되기 때문이다.
FK하나로 양쪽을 다 알 수 있다.
하지만 객체의 연관관계는 그렇지 않기 때문에, 추가로 Team에도 member를 넣어줘야한다.
Team이 여기서는 연관관계 주인의 반대편이므로 mappedBy를 넣어주었다.
이제 서로서로 탐색 가능하다.
그런데 이렇게 해서 출력하면 빈 리스트가 출력이 된다
왜?
아직 DB에 반영이 안되었기 때문이다.
이럴땐 강제로 플러쉬를 해주면 된다!
========================= 연관관계의 주인==========================
사실상, 객체의 연관관계는 서로 다른 단방향 2개가 있는 것이고
테이블은 연관관계가 1개가 있는 것이라고 한다.
그러므로, 둘 중 하나로 외래 키를 관리해야한다.
만약 팀에서의 멤버값이 변하고 멤버에서 팀의 값이 바뀐다면,
어느 값일 때 FK를 업데이트 해야하는지가 모호해진다.
** 양방향 매핑 규칙 **
1. 하나를 연관관계의 주인으로 지정하고, 주인만이 FK를 등록,수정할 수 있다.
2. 주인의 반대쪽은 조회만 가능하다.
-> 주인의 반대쪽에서 아무리 수정,등록해도 아무일도 일어나지 않음!
3. 주인은 외래키가 있는 곳을 주인으로!
( 다:1의 관계에서 다 쪽을 주인으로 두자)
=================================================
** 양방향 매핑시 가장 많이 하는 실수 **
1. 연관관계의 주인에 값을 입력하지 않는 경우가 많다고 하니 주의하자.
2. 무조건 항상 '양쪽' 다 값을 입력하는 것이 맞다고한다.
( test case 작성시,,플러쉬 안해준 순수 1차 캐시에서 값 읽어올때..등등의 상황을 위해..)
-> 연관관계 편의 메소드를 생성하자.
( 양쪽에 둘다 생성하면 오류날 수 있으니,
Member에서 team을 넣던지 team에서 member을 넣던지 하면됨 )
<1> Member에 Team을 반영한 경우
<2> Team에서 Member을 넣어준 경우
3. 양방향 매핑시 무한루프를 조심하자!
- lombok의 toString() 은 웬만하면 사용하지 않기
-JSON 생성 라이브러리 사용시,
Controller에서 Entity 자체를 절대 반환하지 않기!!
무조건 DTO로 변환해서 반환하기
------------------------------------------------------정리----------------------------------------------------
1) 설계시 일단 단방향 매핑으로 다 끝낸다고 생각하고, 단방향 매핑으로만 설계완료하기
2) Table 설계 후 객체 설계
3) 개발 단계로 들어간 후, 양방향이 필요하면 추가하해도됨
-----------------------------------------------------------------------------------------------------------------
그림 출처 : 자바 ORM 표준 JPA 프로그래밍
'JPA' 카테고리의 다른 글
[JPA] 상속관계 매핑 & MappedSuperclass (0) | 2021.06.21 |
---|---|
[JPA] 다양한 연관관계 매핑 - N:1/1:N/1:1/N:M (0) | 2021.06.21 |
[JPA] Entity 매핑 - 객체와 테이블, 필드와 컬럼, 기본키 매핑 (0) | 2021.06.18 |
[JPA] 엔티티의 생명주기 & 플러시 (flush) (0) | 2021.05.20 |
[JPA] 영속성 컨텍스트 (Persistence Context) - 1차 캐시,쓰기 지연, 변경 감지 (0) | 2021.05.20 |