[JPA] 연관관계 매핑과 단방향 매핑

ttaho·2023년 12월 11일
0

JPA

목록 보기
3/7

JPA의 핵심은 "객체 지향 프로그래밍과 관계형 데이터베이스 간의 패러다임 불일치를 해결하는 것" 이다.
이것과 가장 직접적으로 관련되어있는 연관관계 매핑에 대해 알아보자.

연관관계가 필요한 이유

기존의 테이블간의 관계와 객체간의 관계의 차이를 알아보자.

시나리오

  • 회원과 팀이 있다.
  • 회원은 하나의 팀에만 소속될 수 있다.
  • 회원과 팀은 다대일 관계다.

위와 같은 시나리오가 있다고 가정하고 객체의 관계와 테이블 관계를 알아보자.

테이블의 연관관계에 맞게 객체를 설계하고 아래의 코드로 작성했다.(참조 대신 외래 키를 그대로 사용)

 @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("TeamA");
 em.persist(team);
 //회원 저장
 Member member = new Member();
 member.setName("member1");
 member.setTeamId(team.getId());
 em.persist(member);

이 상황에서 회원의 팀을 조회 하려면 어떻게 해야할까?

방법은 회원 객체의 teamId로 team을 찾아야 한다.

 //조회
 Member findMember = em.find(Member.class, member.getId()); 
 //연관관계가 없음
 Team findTeam = em.find(Team.class, findMember.getTeamId());

위 처럼 두 객체간에 연관관계가 없다면 member의 team 객체를 꺼내오기 위해서는 계속해서 member를 조회하고, team을 조회해야 한다.
결국 많은 비용이 들게 되고, 객체 지향스럽지 않은 코드가 된다.

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

위 방식의 문제점을 나타내보자.
1. 테이블외래 키로 조인을 사용해서 연관된 테이블을 찾는다.
2. 하지만 객체참조를 사용해서 연관된 객체를 찾는다.
3. 이처럼 테이블과 객체 사이에는 큰 간격이 있다.
이 세 가지 말을 요약한 것이 객체지향과 관계형 DB 사이의 패러다임이 다르다는 말이다

그럼 이것을 JPA는 어떻게 해결하는지 알아보자

단방향 연관관계

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

  • 객체 연관관계
    - Member 객체는 Member.team 필드로 Team 객체와 연관관계를 맺는다.
    • 회원 객체와 팀 객체는 단방향 관계이다. 회원은 Member.getTeam 메소드를 통해 팀을 알 수 있지만, 팀은 Team.getMember를 통해 소속된 회원들을 알 수 없다!
  • 테이블 연관관계
    - 회원 테이블과 팀 테이블은 양방향 관계이다. 회원 테이블의 외래키인 TEAM_ID를 통해 회원과 팀을 조인할 수 있고, 반대로 팀과 회원도 조인할 수 있다.
    • 회원과 팀을 조인
        SELECT *
        FROM MEMBER M
        JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
    • 팀과 회원을 조인
         SELECT *
         FROM TEAM T
         JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID
  • 객체 연관관계와 테이블 연관관계의 가장 큰 차이
    참조를 통한 연관관계는 언제나 단방향이다. 객체간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해야한다.

연관관계 사용

기존의 Member 객체 코드를 아래 처럼 수정했다.

JoinColumn 어노테이션은 생략 가능하다.
@JoinColumn을 생략하면 외래 키를 찾을 때 기본 전략을 사용한다.
기본 전략: 필드명 + _ + 참조하는 테이블의 컬럼명

여기서 @ManyToOne 인 이유는 Member와 Team이 다대일(N:1) 관계 이기 때문이다.

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

이제 setTeam을 통해 Member에 Team을 연관시켜줄 수 있다.

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

Member를 한번 조회를 통해 Member를 가져오고, getTeam 메소드로 Member가 속한 Team도 조회가 가능하다.

// 새로운 팀B
Team teamB = new Team();
teamB.setName("TeamB");
em.persist(teamB);
// 회원1에 새로운 팀B 설정
member.setTeam(teamB);

위와 같이 Team 수정도 가능하다!

profile
백엔드 꿈나무

0개의 댓글