[JPA] 양방향/단방향 연관관계, 연관관계의 주인

jhkim·2022년 11월 13일
0

Spring

목록 보기
4/7

강의를 듣던 중 단방향/양방향 연관관계나 연관관계의 주인이라는 말이 자주 나오는데 잘 이해가 되지 않아 정리한다!

연관관계를 정의할 때, 생각해야 할 것 세 가지가 있다.

  1. 방향: 양방향 혹은 단방향
  2. 연관 관계의 주인
  3. 다중성: 다대일, 일대다, 일대일, 다대다

단방향과 양방향부터 정리해보자.

단방향은 객체 관계에서 한쪽만 참조하는 것이고, 양방향은 양쪽이 서로 참조하는 것을 의미한다.

그렇다면 이 방향은 어떻게 정하면 될까?

비즈니스 로직에서 두 객체가 서로 참조할 일이 있는지 고민해보면 된다.

예를 들어, Team.getMember()가 필요하면 Team->Member를 참조하는 구조이고,
Member.getTeam()이 필요하면 Member->Team을 참조하는 구조일 것이다.

양 쪽 모두 필요하면 양방향 관계로 정의하면 되는 것이다.


테이블은 외래키 하나로 양방향 쿼리가 가능하므로, 방향이라는 개념이 없다.
그러나 객체는 참조용 필드를 가지고 있는 객체만이 연관된 객체를 조회할 수 있다.

  • 테이블: 외래키로 조인을 사용하여 연관된 테이블 찾음
  • 객체: 참조를 사용해서 연관된 객체 찾음

멤버와 팀 관계를 생각해보자.
이 때 멤버가 다, 팀이 1인 관계이므로
멤버 테이블에 외래키가 존재할 것이다.
(무조건 다 쪽에 외래키 존재함)
(
일대일 관계에서는 어디든지 외래키를 둘 수 있음)

앞서 말했듯 테이블에서는 fk를 통해 양방향으로 값을 사용할 수 있지만, 객체는 다르다.

객체 관점에서, Member에서 Team을 참조하는 것은 FK가 있기에 가능하지만 Team에서 Member를 참조하는 것은 불가능하다.

일대다 양방향 예시

@Entity
public class Member{
  @Id
  @GeneratedValue
  @Column(nam="MEMBER_ID") //생략하면 자동으로 만들어줌
  private Long id;

  private String name;

  @ManyToOne
  @JoinColumn(name="TEAM_ID") //연관관계 주인
  private Team team;

}

@Entity
public class Team {
  @Id
  @GeneratedValue
  @Column(nam="TEAM_ID")
  private Long id;

  private String name;

  @OneToMany(mappedBy = "team")//주인x
  List<Member> members = new ArrayList<>();
}

따라서 Team엔티티에 Member 리스트를 만들고, @OneToMany를 통해 반대편에 매핑된 필드를 지정한다.
이제 Team->Member 참조가 가능해졌다.



그렇다면 외래키를 관리하는 엔티티는 둘중 누구지?

-> 양방향에서 연관관계 주인

Member와 Team이 있을 때, 팀의 멤버 정보가 수정되면 Team에서 Member리스트를 불러와 수정해야 할까, 아니면 Member의 setTeam등의 메소드를 통해 수정해야 할까?
객체 패러다임에서는 양쪽 다 문제가 없지만, DB패러다임에서는 연관관계가 하나임을 보장할 필요가 있다. 즉 연관관계의 주인이 필요한 것이다.

연관관계의 주인만이 외래키를 관리(등록, 수정 등)할 수 있고, 주인이 아닌 쪽은 읽기만 가능하다.

여기서 주인은 @JoinColumn,
주인이 아닌 쪽은 mappedBy를 사용할 것이다.



❗외래키가 있는 쪽을 주인으로 정하자❗

Member가 외래키를 가지고 있다.
따라서 Member의 team을 연관관계의 주인으로 지정하고(@JoinColumn), Team의 memberList는 mappedBy을 사용한다.

이렇게 되면 members 등록, 수정이 불가능하고 조회만 가능하다.

단방향 양방향 예시

OrderItem은 내가 주문한 상품이 어떤 상품인지를 알아야 하니까 Item을 참조하는 반면,
Item에서는 나를 주문한 주문내역이 뭐가 있는지 굳이 알 필요가 없으므로

OrderItem->Item 단방향으로 한다!

0개의 댓글