본문 바로가기
[ ORM ]/JPA

[ JPA ] 연관관계 매핑 기초

by 환이s 2024. 3. 7.


 

연관관계 매핑?

연관관계 매핑이란 객체의 참조와 테이블의 외래 키를 매핑하는 것을 의미한다.

JPA에서는 연관 관계에 있는 상대 테이블의 PK를 멤버 변수로 갖지 않고, 엔티티 객체 자체를 통째로 참조한다.

 

실제로 웹 애플리케이션에서 하나의 엔티티 타입만을 이용하는 경우는 많지 않다.

예를 들어 Member Entity, Team Entity가  있을 때, Team은 여러 Member를 갖는 관계를 가지고 있다.

 

물론 단순히 참조하는 것만으로는 연관관계를 맺을 수 없다.

 

매핑하는 방법은 뒤에서 알아보도록 하고,

그전에 연관관계 매핑을 이해하기 위한 3가지 키워드에 대해 알아보자.


방향( Direction )

 

방향에는 단방향양방향이 있다.

 

  • 단방향 관계
    • 두 엔티티가 관계를 맺을 때, 한쪽의 엔티티만 참조하고 있는 것을 의미한다.
  • 양방향 관계
    • 두 엔티티가 관계를 맺을 때, 양 쪽이 서로 참조하고 있는 것을 의미한다.

 

예를 들어 회원과 팀이 있을 때

(회원 -> 팀) 또는 (팀 -> 회원) 둘 중 한쪽만 참조하면 단방향, 양 쪽을 참조하면 양방향이다.

 

데이터 모델링에서는 관계를 맺어주기만 하면 자동으로 양방향 관계가 되어 서로 참조하지만,객체지향 모델링에서는 구현하고자 하는 서비스에 따라 단방향 관계인지,양방향 관계인지 적절한 선택을 해야 한다.


다중성( Multiplictiy )

 

다중성은 관계에 있는 두 엔티티가 다음 중 하나의 관계를 갖는 것을 의미한다.

 

  • @ManyToOne
    • 다대일( N : 1 )
  • @OneToMany
    • 일대다( 1 : N )
  • @OneToOne
    • 일대일( 1 : 1 )
  • @ManyToMany
    • 다대다 ( N : N )

 

예를 들어

하나의 Team은 여러 Member를 구성원으로 갖고 있으므로 Team 입장에서는 Member와 일대다 관계이며,

Member의 입장에서는 하나의 Team에 속하므로 다대일 관계이다.

 

즉, 어떤 엔티티를 중심으로 상대 엔티티를 바라보느냐에 따라 다중성이 다르게 된다.


연관관계의 주인( Owner )

 

연관관계를 관리 포인트는 외래 키인데,

양방향 관계를 맺으면 객체 서로가 외래 키를 가질 수 있게 된다.

 

따라서 두 객체 중 하나를 외래키를 관리해야 한다.

외래 키를 관리하는 객체를 연관관계의 주인이라 한다.

 

테이블과 객체를 설계할 때 외래 키를 가지는 엔티티를 연관관계 주인으로 정하는데,

그 이유는 외래 키를 가진 테이블과 매핑되는 엔티티가 외래 키를 관리하는 것이 효율적이기 때문이다.

 

연관관계 주인만이 외래 키를 관리(등록,수정,삭제)할 수 있으며, 주인이 아닌 객체는 읽기만 가능하다.


단방향 연관관계

 

먼저 예제 코드로 사용될 Member, Team Entity는 다음과 같다.

 

@Entity
public class Member {     

    @Id   
    @GeneratedValue(strategy = GenerationType.IDENTITY)    
    private Long id;     

    @Column(nullable = false)    
    private String username;     

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

// ... getter setter
}

 

@Entity
public class Team {     

    @Id   
    @GeneratedValue(strategy = GenerationType.IDENTITY)    
    private Long id;     

    @Column(nullable = false)    
    private String name;     

// ... getter setter
}

 

예제 코드의 엔티티 관계를 알아보자면 다대일 관계인 즉, N : 1 관계를 지정한 코드입니다.

단방향은 한 쪽의 엔티티가 상대 엔티티를 참조하고 있는 상태이다.

그렇기 때문에 예제 코드에서 Member 엔티티만 @ManyToOne 애노테이션이 있다.

 

 

 

Member 입장에선 Team과 N : 1 관계이므로 @ManyToOne이 된다.

연관관계를 매핑할 때 다중성을 나타내는 애노테이션은 필수로 사용해야 하며,

엔티티 자신을 기준으로 다중성을 생각해야 한다.

 

   @JoinColumn(name = "TEAM_ID")

 

@JoinColumn 애노테이션은 외래 키를 매핑할 때 사용한다.

name 속성에는 대상 외래 키 이름을 지정한다.

 

예제 코드로 알아보자면

Member 엔티티의 경우 Team 엔티티의 id 필드를 외래 키로 가지므로, "Team_Id" 컬럼 네임을 추가해 줬다.

 

그렇다면 Member , Team은 서로 단방향 관계를 맺으므로 외래 키가 생겼기 때문에

Member에서 Team의 정보들을 가져올 수 있다.

 

그런데 만약 Team에서 Member 정보를 가져오고 싶다면 어떻게 해야 할까??

 

데이터 모델링에서는 1: N 관계만 설정해 주면 자동으로 양방향 관계가 되기 때문에

어느 테이블에서든 Join만 해주면 원하는 컬럼들을 가져올 수 있지만, 

 

JPA에서는 양방향 관계를 맺음으로써 해결할 수 있다.


양방향 연관관계

 

Team에서 Member 정보를 가져오기 위해 1: N 관계를 지정했다.

단방향으로 연관관계를 맺었기 때문에 Team 엔티티에만 추가하면 된다. 

 

@Entity
public class Team {     

    @Id   
    @GeneratedValue(strategy = GenerationType.IDENTITY)    
    private Long id;     

    @Column(nullable = false)    
    private String name;    
    
    @OneToMany(mappedBy = "team")    
    private List<Member> members = new ArrayList<>();

// ... getter setter
}

 

 

Team은 Member를 List로 가지며,

연관관계의 주인을 정하기 위해 @OneToManymappedBy 속성을 추가했다.

 

mappedBy

객체의 양방향 연관관계를 맺을 때 관계의 주인을 설정할 때 사용하게 된다.관계를 표현하는 데 있어서 가장 중요한 개념은 "외래키를 누가 갖고 있냐"이다.

 

즉, 양방향일 때 주인이 아닌 엔티티는 mappedBy 옵션에 반대쪽 매핑의 필드 이름을 넣는다.

반대로 주인은 mappedBy 속성을 사용하지 않고, @JoinColumn을 사용한다.

 

주인은 mappedBy 속성을 사용할 수 없으므로 연관관계의 주인이 아닌 Team 엔티티에서 members 필드에

mappedBy의 속성으로 Member 테이블의 Team 필드 이름을 명시해 준다.

 

■ 양방향 연관관계 시 주의점

  • 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정해야 한다.
  • 연관관계 편의 메서드를 생성하는 것이 좋다.
  • 양방향 매핑 시 무한 루프를 조심해야 한다.
    • toString(), lombok(@ToString)
      • ToString()은 해당 클래스의 모든 멤버 변수를 출력한다.
      • 연관관계 매핑이 되어있을 경우 그 객체 역시 출력해야 하기 때문에 데이터베이스 연결이 필요하게 된다.
      • 이런 문제로 인해 연관관계가 있는 엔티티 클래스의 경우 ToString()할 땐 습관적으로 exclude 속성을 사용하는 것이 좋다.
        • exclude는 해당 속성값으로 지정된 필드는 toString()에서 제외해 준다.
    • Controller에서 Entity를 반환하지 말고 DTO을 거쳐서 반환해야 한다.

 

■ 양방향 매핑 정리

  • 단방향 매핑만으로 이미 연관관계 매핑은 완료된다.
  • 양방향 매핑은 반대 방향으로 객체 그래프 탐색 기능이 추가된 것이다.
  • 단방향 매핑을 잘하고, 양방향은 필요할 때 추가하는 것이 좋다.(테이블에 영향을 주지 않음)
  • 연관관계의 주인은 외래 키의 위치를 기준으로 정해야 한다.

마치며

 

오늘은 연관관계 매핑 기초에 대해 알아봤습니다.

엔티티를 설계할 때 객체의 입장과 테이블의 입장을 모두 생각하는 시간을 가지며

JPA를 사용하기 위해 자기개발을 하는 중입니다.

 

다음 포스팅에서 뵙겠습니다.

위 포스팅 글은 김영한님의 자바 ORM 표준 JPA 프로그래밍-기본편을 참고했습니다.

 

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

회사땜에 매일 바쁜 와중에 학원이라도 다닐까 생각했는데 마침 JPA 강의가 생겨서 꿀 타이밍이네요. 저는 이 전에 JPA 책을 보고 공부 했었는데요 궁금했던 점, 업무에 적용하며 고민하고 해결하

www.inflearn.com

 

728x90

'[ ORM ] > JPA' 카테고리의 다른 글

[ JPA ] 상속 관계 매핑  (59) 2024.03.18
[ JPA ] 다양한 연관관계 매핑  (57) 2024.03.13
[ JPA ] Entity Mapping  (77) 2024.02.26
[ JPA ] 영속성 컨텍스트(Persistence Context) 개념 정리 및 사용법  (75) 2024.02.21
[ JPA ] JPA 소개  (59) 2024.02.15