객체의 참조와 테이블의 외래 키를 매핑하는 것이 이 장의 목표다.
연관관계 매핑을 이해하기 위한 핵심 키워드
- 방향: 단방향/ 양방향, 방향은 객체관계에만 존재하고테이블 관계는 항상 양방향임
- 다중성: N:1,1:N, 1:1, N:M
- 연관관계의 주인: 객체를 양방향 연관관꼐로 만들면 연관관계의 주인을 정해야 함
단방향 연관관계
- 객체 연관관계
: 회원 객체는 Member.team 필드(멤버변수)로 팀 객체와 연관관계를 맺는다.
: 회원 객체와 팀 객체는 단방향 관계다.
- 테이블 연관관계
: 회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺는다.
: 회원 테이블과 팀 테이블은 양방향 관계다. TEAM_ID 외래 키 하나로 MEMBER JOIN TEAM과 TEAM JOIN MEMBER 둘 다 가능하다.
- 객체 연관관계 vs 테이블 연관관계 정리
: 객체는 참조(주소)로 연관관계를 맺는다.
: 테이블은 외래 키로 연관관계를 맺는다.
: 참조를 사용하는 객체의 연관관계는 단방향이다.
: 외래 키를 사용하는 테이블의 연관관계는 양방향이다.
: 객체를 양방향으로 참조하려면 단방향 연관관계를 2개 만들어야 한다.
@JoinColumn
- 외래 키를 매핑할 때 사용한다.
- 속성: name, referencedColumnName, foreignKey(DDL), unique, nullable, insertable, updatable, columnDefinition, table
- @JoinColumn 생략하면 외래 키를 찾을 때 기본전략을 사용한다.
: 기본전략: 필드명 + _ + 참조하는 테이블의 컬럼명 ex) team_TEAM_ID 외래 키를 사용한다.
@ManyToOne
- 다대일 관계에서 사용한다.
- 속성: optional(false로 설정하면 연관된 엔티티가 항상 있어야 함), fetch(글로벌 페치 전략 설정), cascade(영속성 전이 기능 사용), targetEntity
연관관계 사용
- 저장
: JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 한다.
- 조회
: 객체 그래프 탐색(객체 연관관계를 사용한 조회)
: 객체지향 쿼리 사용 JPQL
- 수정
: em.update() 같은 메소드 없다. 불러온 엔티티의 값만 변경해두면 트랜잭션을 커밋할 때 플러시가 일어나면서 변경 감지 기능이 작동한다. 그리고 변경사항을 데이터베이스에 자동으로 반영한다.
: 연관관계를 수정할 때도 같은 방식으로 참조하는 대상만 변경하면 나머지는 JPA가 자동으로 처리한다.
- 연관관계 제거
: 연관관계를 null로 설정
- 연관된 엔티티 삭제
: 연관된 엔티티를 삭제하려면 기존에 있던 연관관계를 먼저 제거하고 삭제해야 한다. 그렇지 않으면 외래 키 제약조건으로 인해, 데이터베이스에서 오류가 발생한다.
양방향 연관관계
- JPA는 List를 포함해서 Collection, Set, Map 같은 다양한 컬렉션을 지원한다.
- @OneToMany(mappedBy = "team")
private List<Mebmer> members = new ArrayList<Member>();
연관관계의 주인
- 두 객체의 연관관계 중하나를 정해서 테이블의 외래키를 관리해야 하는데 이것을 연관관계의 주인이라 한다.
- 연관관계의 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있다. 반면에 주인이 아닌 쪽은 읽기만 할 수 있다.
- 연관관계를 주인으로 정할지는 mappedBy 속성을 사용하면 된다.
: 주인은 mappedBy 속성을 사용하지 않는다.
: 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해야 한다.
- 연관관계의 주인을 정한다는 것은 사실 왜래 키 관리자를 선택하는 것이다.
- @ManyToOne은 항상 연관관계의 주인이 되므로 @ManyToOne에는 mappedBy 속성이 없다.
- 객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다.
ex) members1.setTeam(team1); // 회원 -> 팀
team1.getMembers().add(member1); // 팀 -> 회원
연관관계 편의 메소드
- 한 번에 양방향 관계를 설정하는 메소드를 연관관계 편의 메소드라 한다.
- 연관관계를 변경할 때는 기존 연관관계를 삭제하는 코드를 추가해야 한다.
ex) 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);
}
}
- 객체에서 양방향 관계를 사용하려면 로직을 견고하게 작성해야 한다.
정리
- 단방향 매핑과 비교해서 양방향 매핑은 복잡하다. 연관관계의 주인도 정해야 하고, 두 개의 단방향 연관관계를 양방향으로 만들기 위해 로직도 잘 관리해야 한다.
- 연관관계가 하나인 단방향 매핑은 언제나 연관관계의 주인이다.
- 양방향의 장점은 반대방향으로 객체 그래프 탐색 기능이 추가된 것뿐이다.
ex) member.getTeam(); // 회원 -> 팀
team.getMembers(); // 팀 -> 회원 (양방향 매핑으로 추가된 기능)
- 주인의 반대편은 mappedBy로 주인을 지정해야 한다. 그리고 주인의 반대편은 단순히 보여주는 일(객체 그래프 탐색)만 할 수 있다.
- 연관관계의 주인은 외래 키의 위치와 관련해서 정해야지 비지니스 중요도로 접근하면 안 된다.
'JPA > 자바 ORM 표준 JPA 프로그래밍' 카테고리의 다른 글
Chap.7 고급 매핑 (0) | 2021.05.25 |
---|---|
Chap.6 다양한 연관관계 매핑 (0) | 2021.05.23 |
Chap.4 엔티티 매핑 (0) | 2021.05.17 |
Chap.3 영속성 관리 (0) | 2021.05.10 |
Chap.2 JPA 시작 (0) | 2021.05.10 |