연관관계 매핑 기초

2023. 4. 27. 11:38JPA

반응형

단방향 연관관계

 

연관관계 중에선 다대일(N:1) 단방향 관계를 가장 먼저 이해해야 한다.

회원과 팀의 관계를 통해 다대일 단방향 관계를 알아보자.

다대일 연관관계, 다대일, 단방향

 

· 회원과 팀이 있다.

· 회원은 하나의 팀에만 소속될 수 있다.

· 회원과 팀은 다대일 관계다.

▼ 객체 연관관계

  • 회원 객체는 Member.team 필드(멤버변수)로 팀 객체와 연관관계를 맺는다.
  • 회원 객체와 팀 객체는 단방향 관계다. 회원은 Member.team 필드를 통해서 팀을 알 수 있지만 반대로 팀은 회원을 알 수 없다.

▼ 테이블 연관관계

  • 회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺는다.
  • 회원 테이블과 팀 테이블은 양방향 관계다. 회원 테이블의 TEAM_ID 외래 키를 통해서 회원과 팀을 조인할 수 있고 반대로 팀과 회원도 조인할 수 있다.

객체 관계 매핑

 

JPA를 사용해서 매핑해본다.

다대일, 단방향

 

<매핑한 회원 엔티티>

@Entity
public class Member {
   @Id
   @Column(name = "MEMBER_ID")
   private String id;

   private String username;

   //연관관계 매핑
   @ManyToOne
   @JoinColumn(name = "TEAM_ID")  //외래키 매핑(생략 가능. 생략하면 "필드명_테이블 컬럼명")
   private Team team;

   //연관관계 설정
   public void setTeam(Team team) {
      this.team = team;
   }

   //Getter, Setter...
}

<매핑할 팀 엔티티>

@Entity
public class Team {
   @Id
   @Column(name = "TEAM_ID")
   private String id;
   
   private String name;

   //Getter, Setter...
}

 

양방향 연관관계

 

지금까지 회원에서 팀으로만 접근하는 다대일 단방향 매핑을 알아보았다. 이번에는 반대 방향인 팀에서 회원으로 접근하는 관계를 추가하자.

그림과 같이 회원과 팀은 다대일 관계이고, 반대로 팀에서 회원은 일대다 관계이다. 일대다 관계는 여러 건과 연관관계를 맺을 수 있으므로 컬렉션을 사용해야 한다. Team.members를 List컬렉션으로 추가했다.

테이블의 관계는 어떻게 될까?

데이터베이스 테이블은 외래 키 하나로 양방향으로 조회할 수 있다.

두 테이블의 연관관계는 외래 키 하나만으로 양방향 조회가 가능하므로 처음부터 양방향 관계다.

MEMBER JOIN TEAM도 가능하고, 반대인 TEAM JOIN MEMBER도 가능하다.

양방향 연관관계 매핑

 

<매핑한 회원 엔티티> - 변경한 부분이 없다.

@Entity
public class Member {
   @Id
   @Column(name = "MEMBER_ID")
   private String id;

   private String username;
   
   @ManyToOne
   @JoinColumn(name = "TEAM_ID")
   private Team team;

   //연관관계 설정
   public void setTeam(Team team) {
      this.team = team;
   }

   //Getter, Setter...
}

<매핑한 팀 엔티티>

@Entity
public class Team {
   @Id
   @Column(name = "TEAM_ID")
   private String id;

   private String name;

   //==추가==//
   @OneToMany(mappedBy = "team")
   private List<Member> members = new ArrayList<Member>();

   //Getter, Setter ..
}

팀과 회원은 일대다 관계다. 따라서 팀 엔티티에 컬렉션인 List<Member> members 를 추가했다. 그리고 일대다 관계를 매핑하기 위해 @OneToMany 매핑정보를 사용했다. mappedBy 속성은 양방향 매핑일 때 사용하는데 반대쪽 매핑의 필드 이름을 값으로 주면 된다.

연관관계의 주인

 

단순히 @OneToMany 만 있으면 되지 mappedBy는 왜 필요할까?

엄밀히 이야기하면 객체에는 양방향 연관관계라는 것이 없다. 서로 다른 단방향 연관관계 2개를 애플리케이션 로직으로 잘 묶어서 양방향인 것처럼 보이게 할뿐이다. 반면에 데이터베이스 테이블은 앞서 설명했듯이 외래 키 하나로 양쪽이 서로 조인할 수 있다. 따라서 테이블은 외래 키 하나만으로 양방향 연관관계를 맺는다.

객체 연관관계는 다음과 같다.

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

테이블 연관관계는 다음과 같다.

  • 회원 ↔ 팀의 연관관계 1개 (양방향)

엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래키를 관리하면 된다. 그런데 엔티티를 양방향으로 매핑하면 서로를 참조하므로 객체의 연관관계를 관리하는 포인트는 2곳으로 늘어난다.

엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래키는 하나다. 따라서 둘 사이에 차이가 발생한다.

이런 차이로 인해 JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야 하는데 이것을 연관관계의 주인이라 한다.

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

어떤 연관관계를 주인으로 정할지는 mappedBy 속성을 사용하면 된다.

  • 주인은 mappedBy 속성을 사용하지 않는다.
  • 주인이 아니면 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해야 한다.

그렇다면 Member.team, Team.members 둘 중 어떤 것을 연관관계의 주인으로 정해야 할까?

연관관계의 주인을 정한다는 것은 사실 외래키 관리자를 선택하는 것이다. 여기서는 회원 테이블에 있는 TEAM_ID 외래키를 관리할 관리자를 선택해야 한다.

만약 회원 엔티티에 있는 Member.team을 주인으로 선택하면 자기 테이블에 있는 외래키를 관리하면 된다. 하지만 팀 엔티티에 있는 Team.members를 주인으로 선택하면 물리적으로 전혀 다른 테이블의 외래키를 관리해야 한다. 왜냐하면 이 경우 Team.members 가 있는 Team 엔티티는 TEAM 테이블에 매핑되어 있는데 외래키는 MEMBER 테이블에 있기 때문이다.

연관관계의 주인은 외래키가 있는 곳

 

연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정해야 한다. 여기서는 회원 테이블이 외래키를 가지고 있으므로 Member.team이 주인이 된다. 주인이 아닌 Team.members 에는 mappedBy="team" 속성을 사용해서 주인이 아님을 설정한다.

class Team {
   @OneToMany(mappedBy = "team")
   private List<Member> members = new ArrayList<Member>();
   ...
}

반응형

'JPA' 카테고리의 다른 글

다양한 연관관계 매핑 (2)  (0) 2023.04.27
다양한 연관관계 매핑 (1)  (0) 2023.04.27
엔티티 매핑  (0) 2023.04.27
영속성 관리 (2)  (0) 2023.04.27
영속성 관리 (1)  (0) 2023.04.27