[TIL] 항해99 35일차

심우진·2021년 10월 19일
0

객체 관계 매핑(ORM)에서 가장 어려운 부분이 객체 연관관계와 테이블 연관관계를 매핑하는 일이다.
연관관계를 매핑할 때 다음 3가지를 고려해야 한다.

방향(Direction)
[단방향, 양방향] 존재
회원, 팀 관계가 있을 때
회원 → 팀 또는 팀 → 회원 둘 중 한 쪽만 참조한다면 단방향
회원 → 팀, 팀→ 회원 양쪽 모두 서로 참조하는 것은 양방향 관계
방향은 객체관계에만 존재하고, 테이블은 항상 양방향
다중성(multiplicity)
[다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)] 존재
회원, 팀 관계가 있을 때
여러 회원은 한팀에 속하므로 회원 : 팀 = N : 1
한팀에 여러 회원에 속하므로 팀 : 회원 = 1 : N
연관관계의 주인(owner)
객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 한다.

단방향 연관관계

객체 연관관계와 테이블 연관관계의 가장 큰 차이

참조를 통한 연관관계는 언제나 단방향이다. 객체간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해서 참조를 보관해야 한다. 결국 연관관계를 하나 더 만들어야 한다. 하지만 이것은 엄밀히 말하면 양방향 관계가 아니라 서로 다른 단방향 관계 2개다. 반면에 테이블은 외래 키 하나로 양방향으로 조인할 수 있다.

단방향 관계(A->B)

class A{ B b; 
} 
class B {}

양방향 관계(A<->B)

class A { B b; 
} 
class B {
A a; 
}

객체 연관관계 vs 테이블 연관관계 정리

  • 객체는 참조(주소)로 연관관계를 맺는다.
  • 테이블은 외래 키로 연관관계를 맺는다.
  • 참조를 사용하는 객체의 연관관계는 단방향이다.
    A → B (a.b)
    외래 키를 사용하는 테이블의 연관관계는 양방향이다.
    A JOIN B , B JOIN A 둘다 가능하며 결과값도 같다.

객체 관계 매핑하기

테이블의 구조가 위와 같을 때, JPA를 사용해서 둘의 관계를 매핑해보자.
회원 엔티티


팀 엔티티

회원 엔티티는 팀 엔티티에 N:1(단방향) 관계를 갖는다.

@JoinColumn

@JoinColumn은 외래키를 매핑할 때 사용한다.

@ManyToOne

다대일 관계에서 사용한다.

양방향 연관관계

지금까지 알아본것은 회원에서 팀으로만 접근하는 다대일 단방향 매핑이었다.
이번에는 반대 방향인 팀에서 회원으로 접근하는 관계를 추가하여 회원 → 팀, 팀 → 회원으로 접근할 수 있도록 양방향 연관관계 매핑을 해보자
팀 엔티티에 회원 엔티티를 추가하자
팀 엔티티

팀 엔티티에 컬렉션인 List를 추가하였고, @OneToMany 매핑 정보에 mappedBy 속성을 줬다.
mappedBy 속성은 양방향 매핑일 때만 사용하는데, 반대쪽 매핑의 필드 값을 주면된다. (Member 클래스의 Team 매핑 필드값인 team)

연관관계의 주인

@OneToMany의 mappedBy는 왜 필요한 것일까?
사실 객체에는 양방향 연관관계라는 것이 없고, 서로 다른 단방향 연관관계 2개를 묶어서 양방향인 것처럼 보이게 하는 것이다. (반면에 데이터베이스는 외래 키 하나로 양쪽이 서로 조인할 수 있음. 따라서 외래 키 하나만으로 양방향 연관관계를 맺음)

객체 연관관계는 아래와 같다

  • 회원 → 팀 연관관계 1개(단방향)

  • 팀 → 회원 연관관계 1개(단방향)

    테이블 연관관계

  • 회원 ←> 팀 연관관계 1개(양방향)

    엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래키를 관리하면된다.
    그런데 엔티티를 양방향으로 매핑하면 회원 → 팀, 팀 → 회원 두곳에서 서로를 참조한다. 따라서 객체의 연관관계를 관리하는 포인트가 2곳으로 늘어난다.
    엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래 키는 하나다. 따라서 둘 사이에 차이가 발생한다. (어디서 외래 키를 관리해야 할까?)
    이런 차이로 인해 JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야 하는데 이것을 연관관계의 주인(Owner)라고 한다.

양방향 매핑의 규칙 : 연관관계의 주인

양방향 매핑 시에는 두 연관관계 중 하나를 연관관계의 주인으로 정해야한다.
연관관계 주인만이 데이터베이스 연관관계와 매핑되고 외래 키를 관리(등록, 수정, 삭제)할 수 있다. 주인이 아닌 쪽은 읽기만 할 수 있다.

  • 주인은 mappedBy를 사용하지 않는다.

  • 주인이 아니면 mappedBy를 사용하여 주인을 지정해야 한다.

    => 연관관계의 주인은 외래 키가 있는 곳으로 설정해야 한다. 즉 위의 예에서 보면 외래키 team_id를 갖고있는 member테이블 즉, Member엔티티를 주인으로 설정해야 한다.

    사실은 객체 관점에서 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전하다. 이 부분은 편의 메소드를 만들어 두 객체의 관계를 저장하거나 삭제할 수 있다.

0개의 댓글