본문 바로가기
JPA/자바 ORM 표준 JPA 프로그래밍

Chap.5 연관관계 매핑 기초

by devwari 2021. 5. 19.

객체의 참조와 테이블의 외래 키를 매핑하는 것이 이 장의 목표다.

 

연관관계 매핑을 이해하기 위한 핵심 키워드

- 방향: 단방향/ 양방향, 방향은 객체관계에만 존재하고테이블 관계는 항상 양방향임

- 다중성: 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