참고
연관관계 매핑시 고려사항 3가지
NOTE
다중성
•
다대일 : @ManyToOne
•
일대다 : @OneToMany
•
일대일 : @OneToOne
•
다대다 : @ManyToMany
◦
다대다는 실무에서 사용하지 않는게 좋다!
단방향, 양방향
•
테이블
◦
외래키 하나로 양쪽 join가능
◦
방향이라는 개념이 없음
•
객체
◦
참조형 필드가 있는 쪽으로만 참조가능
▪
한 쪽만 참조하면 단방향
▪
양쪽이 서로 참조하면 양방향
연관관계의 주인
•
테이블은 외래 키 하나로 두 테이블의 연관관계를 맺음
•
객체 양방향 관계는, A B가 아닌, A B, B A처럼 참조가 2곳임
@ManyToOne - 다대일(N:1)
NOTE
객체 양방향 관계에서 연관관계의 주인은 항상 다 (Many)쪽이다.
•
ex) 회원(Many)과 팀(One)이 있다면 회원 쪽이 연관관계의 주인이다.
주요속성
속성 | 설명 | 기본값 |
mappedBy | 연관 관계의 주인 필드를
선택한다. | TRUE |
fetch | 글로벌 패치 전략 설정 | @ManyToOne = FetchType.EAGER
@OneToMany = FetchType.LAZY |
cacade | 영속성 전이 기능을 사용한다. | |
targetEntity | 연관된 엔티티의 타입 정보를 설정한다.
(거의 사용안함) |
@ManyToOne - 단방향
NOTE
Member → Team 참조
•
가장 많이 사용하는 연관관계
@ManyToOne - 양방향
NOTE
Member와 Team이 서로 참조함
•
외래 키가 있는 쪽(Many)이 연관관계의 주인이다.
•
연관관계의 주인이 아닌 쪽은, 단순 조회만 가능하기에 필드만 추가해주면 된다.
@OneToMany
private List<Member> members = new ArrayList<>();
Java
복사
@OneToMany - 일대다(1:N)
NOTE
일(One)이 연관관계의 주인이다.
•
권장하는 방법이 아니다. (실무에서도 거의 사용되지 않음)
권장하지 않는 이유
NOTE
1.
테이블에서는 항상 다(Many)쪽에 외래키가 있기 떄문에 패러다임 충돌이 존재한다.
2.
실무에서 테이블이 수십개 이상 운영이 되는데, 관리 및 트레이싱이 어렵다.
•
Ex) 일대다(1:N)에서 저장이 될 때 양 쪽 객체를 저장한 뒤 update query를 통해 외래키를 설정해야한다. (3번이나 수행)
결론
•
기본은 단방향 다대일(N:1)로 구현하고 필요에 의해 양방향 다대일(N:1)관계를 수립하자.
@OneToMany - 단방향
NOTE
Team.members의 값에 따라 Member의 FK가 관리가되는 구조
•
테이블의 일대다 관계는 항상 다(Many)쪽에 외래 키가 있다
•
객체와 테이블의 차이 떄문에 반대편 테이블의 외래키를 관리하게 됨.
@ManyToOne - 양방향
NOTE
•
이런 매핑은 공식적으로 존재하지 않지만, 설정을 통해서 구현은 할 수 있다.
/* 팀(Team) */
public class Team{
...
@OneToMany
@JoinColumn(name="TEAM_ID")
private List<Member> members = new ArrayList<>();
...
}
Java
복사
/* 멤버(Member) */
public class Member{
...
@ManyToOne
@JoinColumn(name="TEAM_ID", insertable=false, updatable=false)
private Team team;
...
Java
복사
◦
양쪽다 주인이 되지만, Member는 생성과 수정이 불가능해지게 만들었다.
@OneToOne- 일대일(1:1)
NOTE
일대일 관계는 주 테이블이나 대상 테이블 중 누가 외래 키를 가질지 선택해야 한다.
주 테이블에 왜래키
•
주 테이블에 외래키를 두고 대상 테이블을 참조한다.
•
주 테이블에서 대상 테이블과의 연관관계 처리가 쉽다.
대상 테이블에 외래 키
•
대상 테이블에 외래키를 두고 주 테이블을 참조한다.
•
테이블 관계를 일대일 → 일대다로 변경할 떄 테이블 구조를 그대로 유지할 수 있다.
@OneToOne- 단방향
NOTE
외래 키 - 주 테이블
@Entity
public class Member {
// ...
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
}
Java
복사
일대일 단방향 관계 코드
외래 키 - 대상 테이블 (지원안함)
JPA에서 대상 테이블에 FK가 있는 일대일 단방향 관계는 지원하지 않는다
@OneToOne- 양방향
NOTE
어떤 테이블에 FK를 두는지 차이가 있을 뿐 동일하다
외래 키 - 주 테이블
@Entity
public class Member {
// ...
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
}
Java
복사
주인
@Entity
public class Locker {
// ...
@OneToOne(mappedBy = "locker")
private Member member;
}
Java
복사
외래 키 - 대상 테이블
@Entity
public class Member {
// ...
@OneToOne(mappedBy = "member")
private Locker locker;
}
Java
복사
@Entity
public class Locker {
// ...
@OneToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
}
Java
복사
주인
@ManyToMany 다대다(N:N)
NOTE
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
•
그래서 보통 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다.
◦
@JoinTable로 연결 테이블 지정
@ManyToMany - 문제점
NOTE
•
연결 테이블을 자동으로 생성해주는 방식이 편해보이지만, 실무에서 안쓴다.
•
연결 테이블이 단순히 연결만 하는게 아니라, 다른 데이터도 포함되기 떄문이다.
◦
@JoinTable로 생성하면, 테이블의 FK만 받아서 생성된다.
◦
추가적인 데이터를 넣지 못함
•
중간 테이블이 숨겨져 있기 때문에, 의도치 않은 쿼리가 발생할 수도 있다.
@ManyToMany - 문제점 해결(연결 Entity 사용)
NOTE
•
연결 테이블용 Entity를 추가해준다. (연결 테이블을 엔티티로 승격)
•
@ManyToMany → @OneToMany, @ManyToOne
[ 참고]
•
연결 테이블용 Entity에서 각 FK를 복합키 PK 선언도 가능하지만, 새로운 PK를 생성해주는 것이 좋다.