티스토리 뷰

1. 단방향 연관관계


 - 회원은 하나의 팀에만 소속될 수 있다.

 - 팀에는 여러 회원을 가지고 있다.


먼저 위의 경우는 N (회원) : 1 (팀) 의 관계이다. 서로의 연관관계를 결정할 때, 항상 헷갈리고 어렵다. 이럴때 가장 좋은 방법은 역지사지의 방법이다.

반대편의 입장을 결정하는 방법이다. 예를들어, 회원의 입장에서는 하나의 팀에만 소속될 수 있기 때문에 팀은 1이고, 팀의 입장에서는 여러 회원을 가질 수 있기 

때문에 회원은 N 이다. 결론적으로 N : 1 의 관계이다. 이렇게 생각하면 어렵지 않다! 나는 항상 헷갈렸다!


위와 같은 경우에는 객체의 연관관계와 테이블의 연관관계가 서로 다르다. 객체의 연관관계에서는 회원 객체는 Member.team 필드로 팀과 연관관계를 가진다.

회원은 Memeber.team 필드를 이용해 팀의 정보를 가질 수 있지만, 반대로 팀은 회원의 정보를 알 수 없다. 단방향 연관관계이다.

반면에 테이블의 연관관계에서는 회원 테이블의 TEAM_ID 외래키를 통해 팀 테이블과 조인을 할 수 있으며, 팀 테이블 또한 회원 테이블과 조인을 통해 

연관관계를 가질 수 있다. 이 경우에는 양방향 연관관계이다.


객체는 참조를 통해 연관관계를 가지고, 테이블은 외래키를 이용해 연관관계를 가진다. 또한, 테이블은 조인을 통해 양방향 연관관계를 가질 수 있지만, 객체는

참조를 이용해 단방향 연관관계를 두개 설정함으로써 양방향 연관관계와 같이 지원한다. (팀 객체는 List<Member> 가지고, 멤버 객체는 Team 을 가지는 방식)

객체는 참조를 통해 연관관계를 탐색하는데 이를 객체 그래프 탐색이라고 부른다.


<<Member.class>>

@ManyToOne     // (N : 1 관계) , Default -> FetchType.EAGER (즉시로딩)

@JoinColumn(name = "TEAM_ID")    // 외래키를 매핑할 때 사용하며, 외래키의 이름 : '필드명_참조하는 테이블의 칼럼명'

private Team team;


2. 양방향 연관관계


테이블의 연관관계에서는 외래키를 이용해서 양방향 연관관계를 지원하기 때문에 변경할 내용이 없다. 하지만 객체의 연관관계는 단방향 관계 2개를 이용해서 

연관관계를 만들기 때문에 서로의 객체가 참조할 수 있는 필드가 필요하다. 위의 예를 이용해보면, 회원과 팀이 N : 1 의 관계였다면, 팀과 회원은 반대로 1 : N 의 관계이다. 서로를 참조할 수 있는 필드가 필요하다. 


<<Team.class>>

@OneToMany (mappedBy = "team")    // 양방향 매핑일 때 사용하는데 반대쪽 매핑의 필드를 이름으로 주면 된다. 양방향 연관관계에서 '하인' 역할

private List<Member> members = new ArrayList<>();


위에서 mappedBy 옵션이 붙은 객체를 '하인'이라고 칭하였다. 그렇다면 주인은 Member 일 것이다. 여기서 말하는 주종관계는 무엇일까?

단방향에서는 객체의 연관관계를 관리하는 포인트가 하나였다면, 양방향 연관관계는 단방향 연관관계가 두개이므로 관리 포인트가 두개로 늘어난다.

그렇다보니 객체의 참조는 둘인데, 외래키는 하나이기 때문에 문제가 발생할 수 있다. 그렇기 때문에 외래키를 관리하는 관리자가 필요한데, 이 관리자를 주종관계에서 주인의 역할을 하게 된다. 그리고 연관관계의 주인만이 외래키를 등록, 수정, 삭제할 수 있다. 반면에 하인의 역할에서는 오직 읽기만 가능하다.

N : 1, 1 : N 의 관계에서 항상 N에 해당하는 객체가 주인이다. 그 이유는 List를 이용해서 여러 개의 외래키를 관리하는 것보다 하나의 필드에서 외래키를 관리하는 것이 더 효율적이라서 그러지 않을까?


양방향 연관관계에서 주인만이 외래키 등록, 수정, 삭제할 수 있다. 그렇다면 하인은 값을 저장하지 않아도 될까? 사실은 두 객체의 관점에서 모두 값을 입력하는 것이 가장 안전하다. 양쪽 모두 값을 입력하지 않으면, JPA를 사용하지 않는 순수한 객체의 입장에서는 문제가 발생 할 수 있다.


member1.setTeam(teamA);

member1.setTeam(teamB);

Member findMember = team.getMember();


위의 코드에서 teamA에서는 여전히 member1이 조회 가능하다. 그 이유는 Member1은 TeamB로 설정함으로써 TeamA와의 연관관계는 끊어졌지만,

TeamA의 입장에서는 아직 연관관계가 남아 있기 때문이다. 영속성 컨텍스트가 아직 살아 있는 상태에서 문제가 발생 가능하다.

만약 영속성 컨텍스트가 종료된 상태였다면, Team은 하인이기 때문에 외래키에 대한 관리 권한이 없어서, Member와 Team의 관계가 완전히 끊겼을 것이다.

하지만 안정적인 설계를 위해서는 두 객체 관점에서 모두 관리하는 것이 안정적이다. 


공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함