연관관계 매핑 기초
엔티티들은 대부분 다른 엔티티와 연관관계가 있다.
그런데 객체는 참조(주소)를 사용해서 관계를 맺고 테이블은 외래키를 사용해서 관계를 맺는다.
- 방향
- 단방향 : 한 쪽만 참조
- 양방향 : 양쪽 모두 서로 참조
방향은 객체 관계에서만 존재하고 테이블 관계에서는 항상 양방향이다.
-
다중성
다대일, 일대다, 일대일, 다대다 다중성이 있다. - 연관관계의 주인
객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 한다.
1. 단방향 연관관계
1-1 다대일(N:1) 단방향 관계
예) Member —(N, 1)— Team
-
객체 연관관계와 테이블 연관관계의 가장 큰 차이
참조를 통한 연관관계는 언제나 단방향이다. 객체간에 연관관계를 양방향으로 만들고 싶으면
반대쪽에도 필드를 추가해서 참조를 보관해야 한다. 결국 연관관계를 하나 더 만들어야 한다.
하지만 이는 서로 다른 반방향 관계 2개라고 할 수 있다.
반면에 테이블은 외래키 하나로 양방향으로 조인할 수 있다. -
객체 연관관계 vs 테이블 연관관계
객체 연관관계는 데이터를 조회할 때
객체는 참조(주소)를 사용하지만 테이블은 조인(JOIN)을 사용한다.- 참조를 사용하는 객체의 연관관계는 단방향이다.
- 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 한다.
A -> B (a.b)
B -> A (b.a) - 외래 키를 사용하는 테이블의 연관관계는 양방향이다.
A JOIN B
가 가능하면 반대로B JOIN A
도 가능하다.
-
예제 코드
// Member.java
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
// Team.java
@OneToMany
private List<Member> members;
@ManyToOne
다대일 관계라는 매핑 정보이다.
연관관계를 매핑할 때 이렇게 다중성을 나타내는 어노테이션을 필수로 사용해야 한다.
@JoinColumn(name="TEAM_ID")
조인 컬럼은 외래 키를 매핑할 때 사용한다.
name
속성에는 매핑할 외래 키 이름을 지정한다.
이 어노테이션은 생략할 수 있다.
2. 양방향 연관관계
회원에서 팀으로 접근하고 반대 방향인 팀에서도 회원으로 접근할 수 있도록 양방향 연관관계로 매핑해보자.
객체 연관관계
일대다 관계는 여러 건과 연관관계를 맺을 수 있으므로 컬렉션을 사용해야 한다.
Team.members
를 List 컬렉션으로 추가할 수 있다.
객체 연관관계를 정리하면 다음과 같다.
- 회원 -> 팀 (Member.team)
- 팀 -> 회원 (Team.members)
테이블 연관관계
데이터베이스 테이블은 외래 키 하나로 양방향으로 조회할 수 있다.
- 예제 코드
// Member.java
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
public void setTeam(Team team){ // 연관관계 설정
this.team = team;
}
// Team.java
@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<Member>();
팀과 회원은 일대다 관계이기 때문에 팀 엔티티에 컬렉션인 List<Member> members
를 추가했다.
mappedBy
속성은 양방향 매핑일 때 사용하는데 반대쪽 매핑의 필드 이름을 값으로 주면 된다.
이렇게 양방향 매핑을 완료하면 팀에서 회원 컬렉션으로 객체 그래프를 탐색할 수 있다.
3. 연관관계의 주인
`mappedBy’는 왜 필요할까?
객체에는 양방향 연관관계라는 것이 없다.
테이블 연관관계는 다음과 같이 양방향 연관관계가 가능하다.
회원 <-> 팀
엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나다.
그렇다면 둘 중 어떤 관계를 사용해서 외래 키를 관리해야 할까?
=> 둘 사이에 차이가 발생
JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래 키를 관리해야 하는데
이것을 연관관계의 주인이라고 한다.
(1) 양방향 매핑의 규칙 : 연관관계의 주인
- 방향 연관관계 매핑 시 지켜야할 규칙
- 두 연관관계 중 하나를 연관관계의 주인으로 정해야 한다.
- 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있다.
- 주인이 아닌 쪽은 읽기만 가능하다.
- 주인이 아닌 쪽에서
mappedBy
속성을 사용해서 연관관계의 주인을 지정한다. - 주인은
mappedBy
속성을 사용하지 않는다.