본문 바로가기
Back/JPA

[JPA] 연관관계 매핑, 연관관계 주인

by 은z 2021. 12. 15.

본 포스팅은 김영한 강사의 자바 ORM 표준 JPA 프로그래밍 '기본편' 강의를 수강하며 정리한 내용임을 밝힌다.

DB 테스트 환경은 H2 데이터베이스, IDE는 인텔리제이(community version)를 사용했다.

 


 

"객체와 관계형 데이터베이스 테이블 어떻게 매핑되는지를 이해하는 것"이 JPA의 핵심이라고 한다.

이 부분은 중요한 만큼 여러번 실습해보았는데, 계속 헷갈리는 부분이 있어서 정리해보려고 한다.

연관관계 매핑은 비즈니스 로직, 요구사항에 따라 개발자가 더 적절한 관계를 선택해야 하기 때문에 잘 이해하고 있어야 한다.

 

 

 

1. 연관관계 정의 규칙

 

 

  • 방향 : 단방향, 양방향 (객체 참조)
  • 연관 관계의 주인 : 양방향일 때, 연관 관계에서 관리 주체
  • 다중성 : 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)

 

 

2. 방향 : 단방향, 양방향

- DB는 외래 키 하나를 가지고 양쪽 테이블에 조인하여 접근이 가능하다.( 데이터 베이스는 단방향,양방향 개념이 X)

그러나 객체 세상은 다르다. 참조용 필드가 있어야만 다른 객체를 참조할 수 있다.

두 객체 사이에 하나의 객체만 가지고 참조하면 단방향, 두 객체 모두가 각각 참조용 필드를 가지면 양방향이라고 한다.

더 정확히 말하면 사실상 양방향은 없고, 두 객체가 단방향 참조를 각각 가지는 것을 양방향 관계라고 말하는 것.

 

 

1 ) 단방향 연관 관계

단방향

 

 

 

 

// 팀 저장
Team team = new Team();
team.setName("TeamA");
em.persist(team);

// 회원 저장
Member member = new Member();
member.setName("member1");
member.setTeam(team);  //단방향 연관관계 설정, 참조 저장
em.persist(member);

// ------------ 조회 ------------
//조회
Member findMember = em.find(Member.class, member.getId());
//참조를 사용해서 연관관계 조회
Team findTeam = findMember.getTeam();

 

 

 

2) 양방향 연관관계

양방향

//멤버 엔티티
@Entity
public class Member {
@Id @GeneratedValue
private Long id;

@ManyToOne // 다대일관계 매핑(단방향 연관관계와 동일한 방법)
@JoinColumn(name = "TEAM_ID")
private Team team;
…
}

 

//팀 엔티티
@Entity
public class Team {
@Id @GeneratedValue
private Long id;

@OneToMany(mappedBy = "team")  // 일대다관계 매핑 
List<Member> members = new ArrayList<Member>();
//(컬렉션 추가해주기, mapped by에는 해당 다대일이 매핑되어있는 변수명!)
…
}

// 한 멤버가 속한 팀의 전체 멤버 리스트도 받아올 수 있음
List<Memeber>  members = member.getTeam().getMembers();

결론적으로 정리해보면,

다대일 관계(Member)에는 @ManyToOne만! (단방향과 동일한 방법)

일대다관계(Team)에는 @OneToMany
그리고 컬렉션 추가해주고, mapped by에는 해당 다대일이 매핑되어있는 변수명 넣어주기!

 

 

 

3. 연관관계의 주인

위의 예제를 이어서 말하면, 만약 멤버가 속한 팀을 바꾸고 싶다면?

팀에서 멤버를 바꾸어 줘야할지, 멤버에서 팀을 바꿔줘야 할지 판단이 서지 않는다.

DB 입장에서는 멤버에서 팀아이디인 FK값만 바꾸어 주면 된다.

그렇다면 객체 입장에서는? 헷갈린다. 무얼 바꾸어야 로직상 맞는건지.

 

그래서 양방향 연관관계에서는 주인을 정해야한다!

주인이 FK를 관리하게 해주고, 주인이 아닌 쪽에는 읽기만 가능하게 한다.

 

주인은 외래키가 있는 곳으로 정한다. ( 즉, '다'쪽을 주인으로 )

주인 쪽에는 ▼

@ManyToOne
@JoinColumn(name = "FK 이름")
private Team team;

주인이 아닌 쪽에는 ▼

@OneToMany(mappedBy = "주인의 변수명")
List<Member> members = new ArrayList<Member>();

 

 

 

4. 양방향 설계 할 때 고려할 점.

  • 처음 설계할 때는 단방향 매핑으로 설계함!
  • 필요할 때 양방향은 추가해주면 됨! - 테이블에 영향을 주지 않으니..

⇒ 가능하면 단방향으로 하되, 실무에서 양쪽으로 조회가 필요한 경우에 양방향 매핑을 하자!

댓글