JPA 연관관계 매핑 정리

최혜정

Updated:

Intro

안녕하세요. 최혜정 사원입니다. 다양한 연관관계 매핑에 대해서 정리한 내용을 공유하겠습니다.

1. 연관 관계 매핑 할 때 고려사항

1. 다중성 결정하기

  • 다대일
  • 일대다
  • 일대일
  • 다대다

2. 단방향, 양방향 정하기

  • 테이블의 경우 : ‘방향’이라는 개념이 없고 그냥 외래키로 조인하면 두 테이블이 연관관계를 맺음
  • 객체의 경우 : 연관관계 매핑을 객체 참조하는 방식으로 하여, 참조가 2군데 있어야함 (A>B, B>A)

===> 왜리키를 뭐로 할지, 누가 외래키를 관리할 지 정해줘야 함
===> 연관관계의 주인을 만들어야 함

3. 연관관계의 주인 정해주기
양방향의 경우, 누가 주인(=외래키 관리하는 쪽)인지 정해준다.

2. 일대다 @OneToMany

  • 일대다 단방향 [1:N] : ‘일’이 연관관계 주인임, @JoinColumn을 넣어줘야함
  • 일대다 양방향 [1:N, N:1] : 이보다는 다대일 양방향(‘다’쪽이 주인)을 추천
  • 일대다 관계는 항상 ‘다’ 쪽에 외래키가 있음

만약 ‘일’쪽에서 외래키를 관리(주인)하겠다면 헷갈리기 때문에 비추!

  • 다대일 관계에서 주인은 항상 ‘다’쪽에 있으므로, 다대일 양방향을 추천
  • ‘다’쪽에서 ‘일’쪽을 조회할 일이 없더라도, ‘다를’ 연관관계의 주인으로 설정하자
@Entity
@Getter @Setter
public class Team {
    @Id @GeneratedValue
    @Column(name = "TEAM_ID")
    private String id;

    private String name;

    @OneToMany
    @JoinColumn(name = "TEAM_ID")
    private List<Member> members = new ArrayList<>();
}

@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private String id;

    private String username;
}

3. 다대일 @ManyToOne

  • 다대일 단방향 [N:1] : 주인인 ‘다’쪽에서는 ‘일’쪽 참조 가능하나, 반대는 조회도 불가능
  • 다대일 양방향 [N:1, 1:N] : 서로 참조하면 주인아닌 쪽에서는 조회 가능해짐, 연관관계 편의 메소드를 만들어주면 좋음
  • 객체 양방향 관계에서 연관관계의 주인은 항상 다 쪽이다.
@Entity
@Getter @Setter
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private String id;

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

@Entity
@Getter @Setter
public class Team {
    @Id
    @Column(name = "TEAM_ID")
    private String id;
    
    @OneToMany(mappedBy = "team") // 양방향
    private List<Member> members = new ArrayList<>();
}

4. 일대일 @OneToOne

  • 주 테이블이나 대상 테이블, 둘 중 어디에나 외래키 넣어도 가능하다.
  • 일대일 양방향일때는 주인이 아닌쪽에 mappedBy 를 걸어주면 된다.
  • 일대일 양방향일때 다대일 양방향 매핑처럼 외래키가 있는 곳이 연관관계 주인

    • 주 테이블에 외래키 : 객체지향 개발자들이 선호하는 방식으로, 주 객체가 대상 객체의 참조를 가지는 것 처럼 주 테이블에 외래 키를 두고 대상 테이블을 찾는다.
    • 대상 테이블에 외래키
@Entity
@Getter @Setter
public class Member {
    @Id @GeneratedValue
    @Column(name = "member_id")
    private String id;

    @OneToOne
    @JoinColumn(name = "locker_id")
    private Locker locker;   
}

@Entity
@Getter @Setter
public class Locker {
    @Id @GeneratedValue
    @Column(name = "locker_id")
    private Long id;
    
    // 양방향
    @OneToOne(mappedBy = "locker")
    private Member member;                          
}

5. 다대다 @ManyToMany

  • 객체: 다대다 관계가 가능함
  • 테이블: 기존 테이블 두개만으로 다대다 관계를 만들수 없음
  • @JoinTable로 연결 테이블 지정

보통은 연결 테이블을 추가하여 일대다, 다대일로 풀어냄 @ManyToMany → @OneToMany, @ManyToOne 이렇게 풀어내어 만들자

그림

비추하는 코드

  • 연결 테이블이 단순히 연결만 하는게 아니다.
  • 주문시간, 수량 같은 다른 데이터가 필요할 수 있다.
@Entity
public class Member {
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private String id;
    
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT", //연결테이블 지정
          joinColumns = @JoinColumn(name = "MEMBER_ID"), //외래키
          inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID")) //반대 엔티티의 외래키
     private List<Product> products = new ArrayLit<>();
}

@Entity
public class Product {
    @Id
    @JoinColumn(name = "PRODUCT_ID")
    private String id;
    
    private String name;
}

추천하는 코드
@ManyToMany → @OneToMany, @ManyToOne 로 만들고 + 연결 테이블용 엔티티(Order) 추가

@Entity
public class Member {
  @Id @Column(name = "MEMBER_ID")
  private String id;

  @OneToMany(mappedBy = "member")
  private List<Order> orders = new ArrayList<>();   
}

@Entity // 연결 테이블용 엔티티(Order)
public class Order {
  @Id @GeneratedValue
  @Column(name = "ORDER_ID")
  private Long Id;
   
  @Id
  @ManyToOne
  @JoinColumn(name = "MEMBER_ID")
  private Member member;

  @Id
  @ManyToOne
  @JoinColumn(name = "PRODUCT_ID")
  private Product product;
}

@Entity
public class Product {
  @Id @Column(name = "PRODUCT_ID")
  private String id;

  @OneToMany(mappedBy = "product")
  private List<Order> orders = new ArrayList<>();
}

Tags:

Categories:

Updated:

Leave a comment