0. 개요
- 이전 포스팅에 이어서 연관 관계의 종류에 대해서 알아보자.
1. 일대일(1:1, OneToOne) 관계
a) 일대일 연관 관계란
- 일대일 관계는 그 반대도 일대일 관계다.
- 일대일 관계의 경우, 주 테이블 또는 대상 테이블 중 한쪽에서 FK를 관리한다.
- 즉, 연관 관계의 주인을 선택하는 과정이 자유롭다.
- 다만, DB에서 FK에 유니크(UNIQ) 제약조건이 추가되어야 한다.
* 알아두자!
- UNIQUE 제약 조건이란, 해당 칼럼에 들어가는 값(value)이 고유 값이어야 한다는 제약이다.
- 즉, 중복 값이 존재하지 않는다.
b) 일대일 관계의 예시
- 예를 들어, 선수 1명당 1개의 라커를 할당받는다는 규칙을 테이블로 구현하면 다음과 같다.
- 이를 객체로 구현하면 다음과 같다.
- 앞서 설명했듯이, 일대일 관계는 연관 관계의 주인을 자유롭게 선택할 수 있다.
- 그러므로 다대일 관계와는 다르게, 다음과 같이 반대의 관계도 형성이 가능하다.
c) 일대일 관계 예시 코드 - 단방향
- 위의 관계를 코드로 구현하면 다음과 같다.
- 아래의 예시 코드는 Player 객체를 연관 관계의 주인으로 했을 때이다.
@Entity
public class Player {
@Id @GeneratedValue
@Column(name = "PLAYER_ID")
private Long id;
@Column(name = "PLAYER_NAME")
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
// Getter & Setter 생략
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
// Getter & Setter 생략
}
- 위의 코드를 실행했을 때, 콘솔에서 다음과 같은 결과를 확인할 수 있다.
d) 일대일 관계 예시 코드 - 양방향
- 일대일 관계를 양방향 연관 관계를 형성하면 다음과 같은 구조를 가진다.
- 이를 코드로 구현하면 Locker 객체를 다음과 같이 수정하면 된다.
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Player player;
// Getter & Setter 생략
}
- 이처럼 일대일 연관 관계는 연관 관계의 주인을 선택함에 있어서 자유롭다.
- 다만, FK가 존재하는 테이블이 연관 관계의 주인이 된다는 점은 변함없다.
e) 일대일 관계 예시 코드 - 단방향, 대상 테이블이 FK 관리
- 일대일 관계에서 단방향 매핑 시, 대상 테이블이 FK를 관리하는 경우다.
- 즉, 관계의 주인은 Player 객체고 관계의 대상이 Locker 객체인 경우다.
- 일대일 단방향 매핑에서 관계의 주인이 아닌, 대상 테이블이 FK를 관리하는 관계는 허락되지 않는다.
- JPA에서 단방향 매핑 시 대상 테이블이 FK를 관리하는 관계를 지원하지 않기 때문이다.
- 다만, 양방향 매핑 시에는 가능하다.
f) 일대일 관계 예시 코드 - 양방향, 대상 테이블이 FK 관리
- 일대일 관계에서 양방향 매핑 시, 대상 테이블이 FK를 관리하는 경우다.
- 즉, 관계의 주인은 Player 객체고 관계의 대상이 Locker 객체인 경우다.
- 위의 경우는 대상 테이블이 FK를 관리하는 것이 아니다.
- 사실상 Locker 객체가 연관 관계의 주인이 되는 것이다.
- 그러므로 위의 관계를 구현할 때에는 Locker 객체의 playerId를 관계의 주인(FK)으로 설정한다.
- 즉, 일대일 관계의 양방향 매핑과 동일한 방법으로 관계의 주인이 Locker 객체일 뿐이다.
2. 다대다(N:M, ManyToMany) 관계
- 다대다 연관 관계는 실무에서 사용하지 않는 연관 관계다.
- 그러나 JPA에서 지원하는 연관 관계의 형태이므로 무엇인지 알아보자.
a) 다대다 연관 관계란
- 다대다 연관 관계는 정규화된 RDB에서 표현할 수 없는 형태의 관계다.
- 이를 구현하기 위해서는 연결 테이블이라는 테이블과 테이블 사이의 중간 테이블을 이용하여 구현할 수 있다.
- 그러나 객체의 관점에서는 다대다 연관 관계를 구현할 수 있다.
- Java collections를 이용하여 관계를 맺는 양쪽 객체의 참조 리스트를 가질 수 있기 때문이다.
- 위의 설명과 같이, 객체에서는 가능하지만 RDB에서는 불가능한 관계가 다대다 관계이다.
- 이와 같은 이유로 JPA는 다대다 관계를 연결 테이블을 이용한 매핑 관계로 해석하여 DB에게 전달한다.
b) 다대다 연관 관계 구현
- 다대다 연관 관계를 구현할 때에는 @ManyToMany 어노테이션을 사용한다.
- 이때 @JoinTable을 사용하여 연결할 테이블을 설정한다.
- 다대다 연관 관계는 단방향, 양방향 모두 형성이 가능하다.
- 이를 단방향 매핑으로 구현하면 다음과 같다.
@Entity
public class Player {
@Id @GeneratedValue
@Column(name = "PLAYER_ID")
private Long id;
@Column(name = "PLAYER_NAME")
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
@ManyToMany
@JoinTable(name = "PLAYER_LOCKER")
private List<Locker> lockerList = new ArrayList<>();
// Getter & Setter 생략
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
// Getter & Setter 생략
}
- 위의 코드를 실행하면 다음과 같은 결과를 콘솔에서 확인할 수 있다.
c) 다대다 연관 관계의 한계
- 다대다 연관 관계는 현업에서, 실무에서 사용하지 않는 연관 관계다.
- 사용하지 않는 이유는 다음과 같다.
→ 연결 테이블에는 매핑된 칼럼 외 추가적인 칼럼이 삽입될 수 없다.
→ 그러므로 조회할 수 있는 데이터의 범위가 협소하다.
→ 반드시 연결 테이블을 거쳐서 데이터를 조회해야 하므로 복잡한 쿼리가 생성 및 실행된다.
- 이 외에도 다양한 한계와 문제점이 존재한다.
- 현재 시점에서는 다대다 연관 관계는 현업에서 사용하지 않는다는 정도로 이해하자.
d) 다대다 연관 관계의 해결책
- 다대다 연관 관계의 문제점을 극복하려면 어떻게 해야 할까?
- 이에 대한 해결책은 다음과 같다.
→ 다대다 연관 관계를 OneToMany 또는 ManyToOne 관계로 구조를 변경하고
→ 연결 테이블을 하나의 정식적인 테이블로 구현하여 Entity로써 역할하도록 만든다.
- 이 방법은 다대다 관계를 형성하는 양쪽의 테이블을 모두 참조하는 새로운 테이블을 만드는 방법이다.
- 즉, 다대다 관계를 더 작은 단위의 관계로 쪼개어 직접적인 관계가 아닌 간접적인 관계로 풀어내는 방법이다.
'Back-end > JPA 개념' 카테고리의 다른 글
13. @MappedSuperClass (0) | 2022.04.07 |
---|---|
12. 상속 관계 매핑 (0) | 2022.04.06 |
10. 연관 관계의 종류(일대다, 다대일) (0) | 2022.04.04 |
9. 양방향 연관 관계 사용 시 주의사항 (0) | 2022.04.01 |
8. 양방향 연관 관계의 기본 개념 (0) | 2022.03.31 |
댓글