다대다 관계의 경우 그대로 사용하지 못하고 반드시 정규화를 통해 중간 테이블을 만들어줘야 한다.
이러한 관계가 있을 때 반드시 중간 중간 테이블을 두어 일대다+다대일 형태로 변형해줘야 한다.
JPA에서는 @ManyToMany를 통해 연관관계를 매핑할 경우 하이버네이트가 위와 같은 중간 테이블을 알아서 만들어서 처리해준다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@ManyToMany
@JoinTable(name = "새로 만들어줄 중간 테이블 이름")
private List<Product> products = new ArrayList<>();
}
.
.
.
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToMany(mappedBy = "products")
private List<Member> members = new ArrayList<>();
}
위와 같이 @ManyToMany로 양방향 매핑 되어있을 때 (굳이 양방향이어야 할 필요는 없음. 단방향이어도 괜찮다) Member의 @JoinTable(name = "새로운 테이블 명")을 통해 중간 테이블을 따로 만들어준다.
하지만 이러한 방식은 실무에서 절대로 사용하면 안 된다.
중간테이블을 만들고 PK, FK 쌍을 알아서 매핑해주는 것 까지는 문제가 없는데, 실무 레벨에서는 이러한 테이블 매핑에 필요한 필수적인 정보들 외에도 중간 테이블이 가져야하는 여러 가지 컬럼들이 있을 수 있다.
(예를들어 멤버 - 오더 - 상품 이렇게 되어있을 경우 오더가 발생한 시간이라든가 하는 정보들)
하이버네이트에 의해 생성된 중간 테이블은 관계 설정에 필수적으로 필요한 정보들만 담겨있을 뿐 이러한 비즈니스 로직상 필요한 정보들은 담기지 않는다.
따라서, 실무 단계에서는 @ManyToMany는 절대 사용하지 말아야 한다.
다대다 관계를 사용하고 싶은 경우라면 중간 테이블에 대한 클래스를 직접 만들어서 @ManyToOne과 @OneToMany의 조합을 만들어 사용해야 한다.
중간 테이블을 직접 만들어서 관계를 매핑하면 아래와 같은 형태가 된다.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
.
.
.
@Entity
public class Product {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
.
.
.
@Entity
public class MemberProduct {
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
}
Member(ONE) - (MANY)MemberProduct(MANY) - (ONE)Product
MemberProduct는 Order 정도의 역할이 되겠다.
중간 테이블을 하나의 엔티티 개념으로 사용하면 (MemberProduct -> Order) 이러한 형태를 가질 수 있게 된다.
(ORDER_ID는 Generated Value로 주어진 비즈니스적 의미를 갖지 않는 값)
'김영한님 스프링 강의 정리 > JPA' 카테고리의 다른 글
즉시 로딩과 지연 로딩 (0) | 2021.03.01 |
---|---|
상속 관계 매핑 전략 (JOINED, SINGLE_TABLE, TABLE_PER_CLASS) (0) | 2021.02.25 |
연관관계 매핑과 관계의 주인 (0) | 2021.02.21 |
기본 키 매핑 전략 - IDENTITY, SEQUENCE (0) | 2021.02.21 |
Flush에 대해 (0) | 2021.02.19 |