JPA

[JPA] 단방향 연관관계

수수한개발자 2022. 5. 9.
728x90

JPA 연관관계 중 단방향 연관관계에 대해서 알아보겠습니다.

1.연관관계가 필요한 이유

요구사항 

- 회원과 팀이 있다.

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

-회원과 팀은 다대일 관계이다.

 

객체 테이블에 맞추어 모델링(참조 대신 외래키를 그대로 사용)

아래는 회원과 팀 클래스 입니다.

 

@Entity
public class Member {

  @Id @GeneratedValue
  private Long id;

  @Column(name = "USERNAME") 
  private String name;

  @Column(name = "TEAM_ID")
  private Long teamId;
  ...
  }

@Entity
public class Team {

  @Id @GeneratedValue
  private Long id;
  private String name;
  ...
  }

 

아래는 팀과 회원을 저장하는 코드입니다.

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

//회원 저장
Member member = new Member();
member.setName("conas");
member.setTeamId(team.getId());
em.persist(member);

여기서 연관관계가 없다면 회원의 팀을 찾으려면 어떻게 해야 할까요?

Member findMember = em.find(Member.class, member.getId());

Long findTeamId = findMember.getId();
Team findTeam = em.find(Team.class, findTeamId);

위와 같이, member에서 teamId를 가져오고 그 teamId로 다시 Team을 가져오는 작업을 반복하게 됩니다.

한 눈에 봐도 객체 지향스럽지 않고 비용이 많이 듭니다.

 

객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력관계를 만들 수 없습니다.

데이터베이스 테이블들은 외래키로 조인을 사용해서 연관된 테이블을 쉽게 찾는 반면에

객체는 참조하는 값을 만들어줘야하고 그 참조한 값을 이용해 다시 한번 찾아야합니다.

이렇게 객체와 테이블 사이에는 큰 간격이 있습니다.

 

2.단방향 연관관계

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

 

객체 연관 관계

-회원 객체(Member)는 Member.team 필드로 팀 객체와 연관관계를 맺습니다.

-회원 객체와 팀객체는 단방향 관계입니다. 회원은 Member.team 필드를 통해 팀을 알 수 있지만

  팀 객체로 소속된 회원들은 알 수 없기 때문입니다.

 

테이블 연관관계

-회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺습니다.

-회원 테이블과 팀 테이블은 양방향 관계입니다. 회원테이블의 TEAM_ID(FK) 외래 키를 통해서 회원과 팀을 조인 할 수있고, 반대로 팀과 회원도 조인할 수 있습니다.

 

  • 객체 연관관계와 테이블 연관관계의 가장 큰 차이
    참조를 통한 연관관계는 언제나 단방향입니다. 객체간에 연관관계를 양방향으로 만드록 싶으면 반대쪽에도 필드를 추가해서 참조를 보관해야 합니다. 이렇게 양쪽에서 서로 참조하는 것을 양방향 연관관계라고 합니다.
    하지만 정확히 이야기하면 이것은 양방향 관계가 아니라 서로 다른 단방향 관계 2개입니다. 반면에 테이블은 외래 키 하나로 양방향으로 조인할 수 있습니다.

 

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

- 객체는 참조로 연관관계를 맺습니다.

- 테이블은 외래 키로 연관관계를 맺습니다.

- 참조를 사용하는 객체의 연관관계는 단방향입니다.

- 외래키를 사용하는 테이블의 연관관계는 양방향입니다.(A JOIN B 가능하면 B JOIN A 도 가능하다.)

 

연관관계 사용

Member, Team Class

@Entity
public class Member {

  @Id @GeneratedValue
  private Long id;

  @Column(name = "USERNAME") 
  private String name;

  @ManyToOne
  @JoinColumn(name = "TEAM_ID")
  private Team team;
  
  // Getter, Setter ...
}

@Entity
public class Team {

  @Id @GeneratedValue
  private Long id;
  private String name;
  
  // Getter, Setter ...
}

연관관계 저장

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

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

이전과 다른점은 member객체에 teamId가 아니라 Team객체 자체를 넣어준다는 것입니다.

 

참조로 연관관계 조회 - 객체 그래프 탐색

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

 

연관관계 수정

// 새로운 팀B
Team teamB = new Team();
teamB.setName("TeamB");
em.persist(teamB);

// 회원1에 새로운 팀B 설정
member.setTeam(teamB);

 

@ManyToOne, @JoinColumn

@ManyToOne : 다대일(N:1) 관계라는 매핑 정보입니다. 회원과 팀은 다대일 관계입니다. 연관관계를 매핑할 때 이렇게 다중성을 나타내는 어노테이션을 필수로 사용해야 합니다. (안 써주면 JPA가 컴파일오류로 알려주긴함.)

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

@JoinColumn : 외래 키를 매핑할 때 사용합니다.

JoinColumn 어노테이션은 생략 가능합니다. 

생략하면 외래키를 찾을 때 기본 전략을 사용합니다.

기본전략 : 필드명을 참조하는 테이블의 컬럼명

728x90

'JPA' 카테고리의 다른 글

[JPA] 플러시란?  (0) 2022.06.13
[JPA] 영속성 컨텍스트  (0) 2022.05.11
[JPA]기본 키 매핑  (0) 2022.05.08
[JPA] 기본 @Anotation 정리  (0) 2022.05.08
[JPA] 데이터베이스 스키마 자동 생성  (0) 2022.05.08

댓글