JPA

6장 다양한 연관관계 매핑

iksadnorth 2023. 8. 31. 14:18

해당 게시물은 책 '자바 ORM 표준 프로그래밍'을 읽고 작성했습니다.

👣 개요

해당 게시물에서는 '다대일', '일대다', '일대일', '다대다' 의 연관관계를 다룰 예정이었다.
하지만 앞선 5장과 다소 중복이 많기 때문에 '다대다' 관계에 대해서만 다루고 넘어갈 것이다.

 

👣 다대다 연관관계

마치 쇼핑몰 웹사이트에서의 '회원'과 '상품'의 관계와 같다.
이하, '회원'을 A로 '상품'을 B로 표기한다.
A는 여러 개의 B를 소유할 수 있다. 마찬가지로 B는 여러 명의 A에 의해서 주문되어 진다.

안타깝게도 SQL에서는
정규화가 진행된 테이블 2개만으로 이 관계를 정의할 수 없다.
때문에 A와 B 사이에 '주문 테이블'[이하 C]가 추가적으로 필요하다.
이를 통해 A-C 혹은 B-C의 관계를 다시 '다대일'관계로 만들어서 사용할 수 있다.

create table MEMBER (
    ID bigint primary key,
    USERNAME varchar(100)
);

create table PRODUCT (
    ID bigint primary key,
    NAME varchar(100)
);

create table MEMBER_PRODUCT (
    MEMBER_ID bigint,
    PRODUCT_ID bigint,
    
    primary key (MEMBER_ID, PRODUCT_ID),
    foreign key (MEMBER_ID) references MEMBER(ID),
    foreign key (PRODUCT_ID) references PRODUCT(ID)
);

하지만 OOP에서는 
객체 2개로도 다대다 관계를 정의할 수 있다.
단순히 클래스의 필드에 List<?> 타입를 할당하기만 하면 그만이기 때문이다.
때문에 엔티티를 매핑할 때, 단순히 List<?> 타입 필드 위에 @ManyToMany 어노테이션만 
부여하면 된다.

public class Member {
    private Long id;
    private String username;
    private List<Product> products;
}

public class Product {
    private Long id;
    private String name;
    private List<Member> members;
}

당연히 SQL과 OOP와의 간극을 해결하기 위해 @JoinTable이라는 어노테이션을 추가로 
부여해야 한다.

 

👣 연관관계 매핑 어노테이션

@ManyToMany
모든 속성은 orphanRemoval가 없다는 것을 제외하면 @OneToMany와 같다.

 

5장 연관관계 매핑 기초

👣 개요 OOP와 SQL 사이의 가장 큰 간극은 '객체의 참조'와 'table 사이의 관계'일 것이다. OOP의 경우, 어떤 한 객체 A가 다른 객체 B를 필드로서 참조하고 있다고 해도 객체 B가 객체 A를 필드로 가지

ikadnorth.tistory.com

@JoinTable
엔티티로 명시하지 않았지만 다대다 관계를 정의하기 위한 추가 테이블을
알아서 정의하는 어노테이션. 
간단하게 FK로만 이뤄진 2개의 칼럼으로 구성된 테이블을 생성한다.

  • name
    연결 테이블의 이름을 지정한다.
  • joinColumns
    현재 엔티티의 칼럼 중 JoinTable의 FK로 사용할 칼럼을 지정.
  • inverseJoinColumns
    상대 엔티티의 칼럼 중 JoinTable의 FK로 사용할 칼럼을 지정.

결국, [다대다 연관관계]에서 제시한 엔티티는 다음과 같이 매핑할 수 있다.

@Entity @Table(name = "MEMBER")
public class Member {
    @Id
    private Long memId;
    private String username;
    
    @ManyToMany
    @JoinTable(
        name = "MEMBER_PRODUCT",
        joinColumns = @JoinColumn(name = "mem_id"),
        inversejoinColumns = @JoinColumn(name = "pro_id")
    )
    private List<Product> products;
}

@Entity @Table(name = "PRODUCT")
public class Product {
    @Id
    private Long proId;
    private String name;
    
    @ManyToMany(mappedBy = "products")
    private List<Member> members;
}

 

👣 JoinTable의 한계

사실, 편의를 위해서 @JoinTable을 사용하는 거지
실제로 적용하기 위해서는 그냥 직접 Member_Product 엔티티를 만드는 것이 
유지보수에 유리하다. 이유는 다음과 같다.

1. JoinTable에 추가적인 칼럼[생성일자, 거래가격 등]을 생성하면 
적용할 수 없다.

2. 식별 관계가 강제되므로 인조 키를 사용할 수 없다.

위와 같은 이유로 그냥 직접 테이블을 만들어서 2개의 다대일 관계로 매핑하는 것이
뒷탈이 없다.

 

'JPA' 카테고리의 다른 글

8장 프록시와 연관관계 관리  (0) 2023.08.31
7장 고급 매핑  (0) 2023.08.31
5장 연관관계 매핑 기초  (0) 2023.08.30
4장 엔티티 매핑  (0) 2023.08.30
3장 영속성 관리  (0) 2023.08.27