뭐라도 끄적이는 BLOG

JPA 05.01 - 연관관계 매핑, 단방향 연관관계 본문

Java/JPA

JPA 05.01 - 연관관계 매핑, 단방향 연관관계

Drawhale 2021. 4. 16. 07:16

객체가 지향하는 패러다임과 관계형 DB가 지향하는 패러다임이 다르기 때문에 연관관계를 맺는데 어려움이 있습니다. 예를 들어 Member와 Team이 있다면 객체는 Member.getTeam()으로 Team객체를 찾아올 수 있어야 합니다. 하지만 테이블은 이러한 연관관계를 외래키 값을 이용합니다. 이번 연관관계 매핑에서는 이러한 객체와 테이블의 차이를 이해하고 객체의 참조와 테이블의 외래키를 매핑하는 것이 목표입니다.

 

시작하기 앞서 몇가지 용어를 먼저 알아보고 가겠습니다.

방향(Direction) : [ 단방향, 양방향 ] 한쪽만 참조하는 것을 단방향, 양쪽 모두 서로 참조하는 것을 양방향이라고 합니다.

다중성(Multiplicity) : [ N : 1, 1 : N, 1 : 1, N : N ] 관계형 DB의 다중성과 같습니다.

연관관계의 주인(Owner) : 객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 합니다.

 

연관관계가 필요한 이유

객체지향 설계의 목표는 자율적인 객체들의 혐력 공동체를 만드는 것이다. - 조영호(객체지향의 사실과 오해)

시나리오

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

테이블 연관관계를 분석해보면 아래와 같습니다.

  • 회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺는다.
  • 회원 테이블과 팀 테이블은 양방향 관계다. 회원 테이블의 TEAM_ID외래 키를 통해서 회원과 팀을 조인할 수 있고 반대로 팀과 회원도 조인할 수 있다. 예를 들어 MEMBER 테이블의 TEAM_ID 외래 키 하나로 MEMBER JOIN TEAM과 TEAM JOIN MEMBER둘다 가능하다.

먼저 외래 키 하나로 어떻게 양방향으로 조인하는지 알아보겠습니다.

SELECT *
FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
SELECT *
FROM TEAM M
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID

 

차례대로 회원과 팀을 JOIN하는 SQL과 반대인 팀과 회원을 JOIN 하는 SQL입니다. 그리고 이를 통해 테이블에 맞추어 연관관계가 없는 객체를 만들어 보겠습니다.

 

Member.java

@Entity
@Getter
@Setter
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;
    
    @Column(name = "USERNAME")
    private String name;

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

Team.java

@Entity
@Getter
@Setter
public class Team {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY
    @Column(name = "TEAM_ID")
    private Long id;
    private String name;
}

Member와 Team을 Database Table에 맞추어 외래키 값을 그대로 가져오는 설계 했다고 볼 수 있습니다. 보시다시피 이는 객체지향에 적절하지 않은 설계입니다.

Team team = new Team();
team.setName("TeamA");
em.persist(team);

Member member = new Member();
member.setName("member1");
member.setTeamId(team.getId());
em.persist(member);

먼저 Member를 저장하기 위한 코드입니다. member1을 teamA에 소속 시키기위한 setTeamId()가 객체지향스럽지 않습니다. setTeam()이라고 해야 더욱 객체지향 다워질 것입니다.

 

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

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

그리고 Member에서 Team을 가지고 오기 위한 코드입니다. member를 가지고 와서 member에서 teamId를 가지고 오고 또 teamId로 Team을 또 가지고 와야합니다. 결국 회원의 팀을 가지고 오기 위해 많은 비용을 필요로 합니다. 그리고 이 또한 객체지향스럽지 않은 코드가 됩니다.

 

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

테이블은 외래 키로 조인을 사용해서 연관된 테이블을 찾습니다. 그리고 객체는 참조를 사용해서 연관된 객체를 찾습니다. 이 둘간에 이러한 큰 간격이 있습니다. 이러한 차이를 인식을 하는 것이 중요합니다.

 

단방향 연관관계

이번에는 객체에 단방향 연관관계를 만들어서 설계해 보겠습니다.

  • 회원 객체는 Member.team필드로 팀의 객체와 연관관계를 맺는다.
  • 회원 객체와 팀 객체는 단방향 관계다. 회원은 Member.team 필드를 통해서 팀을 알 수 있지만 반대로 팀은 회원을 알 수 없다. 예를 들어 member → team의 조회는 member.getTeam()으로 가능하지만 반대 방향인 team → member를 접근하는 필드는 없다.

 이전엔 TeamId를 가지고 왔지만 이젠 Team의 참조값을 가지고 오게되었습니다. 이를 통해 Member 클래스의 코드도 아래와 같이 변경되었습니다.

@Entity
@Getter
@Setter
public class Member {

    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "MEMBER_ID")
    private Long id;

    @Column(name = "USERNAME")
    private String name;
    
    @ManyToOne
    @JoinColumn(name = "TEAM_ID")
    private Team team;
}

[ N : 1 ]에서 N이되는 Member를 기준으로 Many 1이 되는 Team을 기준으로 One으로 @ManyToOne이라는 Annotation을 사용합니다. 연관관계를 매핑할 때 이렇게 다중성을 나타내는 Annotation을 필수로 사용해야 합니다.

 

@JoinColum을 통해 외래 키를 매핑하게 됩니다. 해당 Annotation은 생략 가능하며 생략하면 외래키를 찾을 때 기본 전략을 사용합니다.

 

이렇게 변경하게 되면 저장하는 코드와 찾는코드 모두 변하게 됩니다.

Team team = new Team();
team.setName("teamA");
em.persist(team);

Member member = new Member();
member.setName("member1");
member.setTeam(team);
em.persist(member);

setTeam()으로 teamId를 직접 넣지 않고 객체를 넣을 수 있게 되었습니다.

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

Team findTeam = findMember.getTeam();

찾는 코드또한 member에서 teamId를 따로 가지고 올 필요 없이 getTeam()으로 바로 객체를 가지고 올 수 있게 되었습니다.

 


 

※ 참고 자료

 

 

자바 ORM 표준 JPA 프로그래밍 - 교보문고

자바 ORM 표준 JPA는 SQL 작성 없이 객체를 데이터베이스에 직접 저장할 수 있게 도와주고, 객체와 관계형 데이터베이스의 차이도 중간에서 해결해준다. 이 책은 JPA 기초 이론과 핵심 원리, 그리고

www.kyobobook.co.kr

 

자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의

JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., 본 강의는 자바 백엔

www.inflearn.com

 

Documentation - 5.4 - Hibernate ORM

Idiomatic persistence for Java and relational databases.

hibernate.org

 

반응형