0. 개요
- 이번 포스팅에서는 다양한 연관 관계의 종류에 대해서 알아보도록 하자.
a) 연관 관계의 종류
- 연관 관계에는 다음과 같은 종류가 있다.
→ 다대일(N:1, @ManyToOne)
→ 일대다(1:N, @OneToMany)
→ 일대일(1:1, @OneToOne)
→ 다대다(N:N, @ManyToMany)
- 위의 4가지 형태의 연관 관계에 대하여 알아보도록 하자.
1. 연관 관계 매핑 시 고려사항
a) 다중성
- 위에서 4가지 종류의 연관 관계가 있다는 것을 알았다.
- 이 연관 관계를 매핑할 때에는 다중성을 고려해야 하는데, 다중성이란 다음과 같다.
ex) 하나의 주문이 여러 개의 아이템을 가지는 관계
ex) 하나의 팀이 여러 명의 선수를 가지는 관계
- 이처럼 연관 관계의 대상이 다수의 데이터를 보유할 수 있는 관계인지를 파악해야 올바른 관계를 형성할 수 있다.
- 즉, DB 관점에서의 다중성을 고려해야 한다.
- 만약 다중성이 헷갈리는 경우, 연관 관계의 대상의 입장에서 생각해보면 된다.
- 모든 관계는 대칭을 이루기 때문이다.
ex) 팀 → 선수는 OneToMany의 관계다. 선수 → 팀은 ManyToOne의 관계다.
* 알아두자!
- 사실 다대다(N:N) 관계는 사용하면 안 되는 연관 관계다.
- 왜 사용하면 안 되는지, 어떻게 대체할 수 있는지 추후에 언급하도록 하겠다.
b) 단방향, 양방향
- 연관 관계의 방향성을 고려해야 올바른 관계를 형성할 수 있다.
- 이전 포스팅에서도 강조한 내용이지만 다시 한번 복습해보자.
- 테이블은 FK를 생성하여 양방향 연관 관계를 형성한다. 그러므로 테이블은 관계의 방향이 애초에 없다.
- 객체는 참조 필드가 존재하는 Entity만 참조가 가능하다.
- 연관 관계에서 참조 필드가 한쪽에만 존재하면 단방향, 양쪽에 모두 참조 필드가 존재하면 양방향 매핑이 된다.
- 즉, 서로를 향하는 단방향 매핑이 2개 있는 것일 뿐 양방향 매핑이 따로 존재하는 것은 아니다.
- 다만, 단방향 매핑으로 모든 관계를 표현할 수 있기에 최초에는 단방향 매핑을 기준으로 설계한다.
- 그러므로 추가적인 조회 기능이 필요한 경우에만 양방향 관계를 형성하는 것을 권장한다.
c) 연관 관계의 주인
- 양방향 매핑을 형성할 때에는 반드시 연관 관계의 주인을 결정해야 한다.
- 그 이유는 다음과 같다.
- 테이블은 FK 하나로 양방향 관계를 형성한다.
- 그러나 객체는 단방향 매핑 2개를 이용하여 양방향 관계를 형성한다.
- 그러므로 객체에서 양방향 매핑을 이용하여 데이터를 삽입할 때, 그 기준을 정해줘야 한다.
- 즉, 객체를 이용하여 데이터를 삽입할 때 어떤 필드가 FK의 역할을 하는지를 JPA에게 알려줘야 하는 것이다.
- 결론적으로 연관 관계 주인을 결정하는 것은 FK를 지정하는 것과 동일하다.
- 연관 관계의 주인을 FK로 FK의 값을 업데이트할 수 있으며, 주인의 반대에 있는 Entity는 값의 조회만 가능하게 된다.
2. 다대일(N:1, ManyToOne) 관계
a) 다대일 연관 관계란
- DB의 관점에서 보면 다대일 연관 관계는 다음과 같은 테이블 구조를 이룬다.
- 다수의 Player는 하나의 Team에 속해있다. (Many To One)
b) ManyToOne의 연관 관계 주인
- 다대일(N:1) 관계는 다수(Many)의 입장이 연관 관계의 주인이 된다.
- 위의 예시에서는 다수(Many)의 입장은 Player가 된다.
- 그러므로 Player가 연관 관계의 주인이 된다.
- 가장 많이 사용하는 연관 관계이다.
3. 일대다(1:N, OneToMany) 관계
a) 일대다 연관 관계란
- DB의 관점에서 보면 일대다 연관 관계는 다음과 같은 테이블 구조를 이룬다.
- 하나의 Team은 다수의 Player를 보유하고 있다. (One To Many)
b) OneToMany의 연관 관계 주인
- 일대다 관계는 일(One)의 입장이 연관 관계의 주인이 된다.
- 그러나 위의 테이블 구조를 살펴보면, FK는 다수(Many)인 Player 테이블에 존재한다.
- 이것이 어떻게 가능할까?
- 검색의 주체가 Team이 되는 것이다. 즉, Team 객체를 이용하여 Player 정보를 검색하는 상황인 것이다.
c) OneToMany 구현의 문제점
- 우선 OneToMany 관계는 실무에서 사용하지 않는 것을 권장하는 구조다.
- RDB 입장에서 고려해보면 일대다의 관계는 올바르지 않은 구조를 갖기 때문이다.
- 그 이유를 차근차근 알아보자.
- 위의 테이블 구조를 객체로 바꿔보면 다음과 같이 형성된다.
- 객체 관점에서 보면, Team이 Player 정보를 요구하는 관계다.
- 다시 말해서 Team 정보를 이용하여 Player 정보를 조회하는 상황이다.
- RDB 관점에서는 다수(Many)의 입장이 FK를 가져야 올바른 설계다.
- 그러므로 FK를 가지는 Entity가 연관 관계의 주인이 되어야 한다.
- 그러나 객체의 연관 관계는 이를 반대로 설정하고 있기 때문에, 처리과정이 복잡해진다.
- 연관 관계의 주인이 Team Entity가 되기 때문에 Team 객체에서 Player의 team_id 값을 변경하는 경우
Player 객체의 team_id를 update 해줘야 한다.
- 조금 이질감이 있지만, 위의 연관 관계를 코드로 작성하면 다음과 같다.
@Entity
public class Player {
@Id @GeneratedValue
@Column(name = "PLAYER_ID")
private Long id;
@Column(name = "PLAYER_NAME")
private String name;
// Getter & Setter 생략
}
@Entity
public class Team {
@Id
@GeneratedValue
@Column(name = "TEAM_ID")
private Long id;
@Column(name = "TEAM_NAME")
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID")
private List<Player> players = new ArrayList<>();
// Getter & Setter 생략
}
* 알아두자!
- OneToMany 관계를 구현할 때에는 반드시 @JoinColum을 사용해야한다.
- @JoinColumn을 사용하지 않으면 default 설정으로 Join Table 방식을 사용하기 때문이다.
- JoinTable 방식을 사용하면 두 테이블을 조인한 중간 테이블이 DB에 추가적으로 생성된다.
- 위의 코드를 바탕으로 데이터를 저장해 보면, 다음과 같은 코드를 작성하게 된다.
- 조금 이상한 부분이 빨간 줄을 친 코드다.
- team 객체를 이용하여 player 정보를 삽입하는 것처럼 보이지만,
- 결국 team 객체를 통해 FK를 가지고 있는 Player 테이블의 team_id 값에 접근하게 된다.
- 위의 코드를 실행시켜보면 다음과 같은 SQL이 콘솔에 출력된다.
- 콘솔에 출력된 내용을 읽어보면 one-to-many 관계에 의해 player 테이블에 update가 실행된 것을 볼 수 있다.
- 더불어, 아래에는 UPDATE 쿼리문이 DB로 전달됨을 확인할 수 있다.
- DB에는 위와 같이 데이터가 잘 저장된 것을 확인할 수 있다.
d) 일대다 관계는 권장하지 않는다.
- 이와 같은 이유로 OneToMany 관계는 구현하는 것을 권장하지 않는다.
- 위의 예제에서는 2개의 테이블만 이용하여 연관 관계를 구축했지만, 실무에서는 수십 또는 수백 개의 테이블이 돌아간다.
- 이와 같은 상황에서 OneToMany 관계를 일일이 신경 쓸 수 없기 때문에 실수가 발생하기 마련이다.
e) 일대다 관계 구현의 해결책
- OneToMany 관계를 ManyToOne 관계로 구현하여 양방향 매핑을 사용하는 것을 권장한다.
- OneToMany 관계라고 할지라도, 객체 구조상 양방향 매핑을 통해 다수(Many)를 담당하는 Entity가
주인이 되도록 설정한다.
'Back-end > JPA 개념' 카테고리의 다른 글
12. 상속 관계 매핑 (0) | 2022.04.06 |
---|---|
11. 연관 관계의 종류(일대일, 다대다) (0) | 2022.04.05 |
9. 양방향 연관 관계 사용 시 주의사항 (0) | 2022.04.01 |
8. 양방향 연관 관계의 기본 개념 (0) | 2022.03.31 |
7. 단방향 연관 관계 (0) | 2022.03.30 |
댓글