책을 읽고 배운 내용을 정리한다.
맵핑은 다대일 단방향부터 생각하자
- JPA는 다양한 연관관계에 대한 맵핑 방법을 제공한다.
- 그중 가장 기본이 되는 방법은 다대일 단방향 맵핑이다.
- 2개의 테이블을 JOIN 했을 때 가장 연상하기도 쉽고 DB 관점에서도, 객체 관점에서도 개발자에게 익숙하다.
- 양방향 맵핑은 필요한 경우에만 만들어주면 된다.
- 단방향, 양방향의 차이는 객체 그래프 탐색의 루트를 한쪽에서만 할 수 있을지, 양 쪽에서 다 가능하게 할지의 차이기 때문이다.
다대다 맵핑
@Entity
@Data
public class Member {
@Id
@Column(name = "MEMBER_ID")
private String id;
@Column
private String username;
// 다대다 매핑
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
private List<Product> products = new ArrayList<>();
}
- 위와 같이 설정하면 다대다 맵핑도 가능하다.
- 주인 엔티티에서 위와 같이 설정해주면 다대다 단방향, 다른 엔티티에서 mappedBy로 연관 관계를 맺어주면 다대다 양방향이 된다.
문제점
- 위 방법처럼 다대다 맵핑을 구현할 수 있지만, 실제 상황에선 고려해야 하는 점이 많다.
- 우선 다대다 관계라는 것은 그 중간에 (일대다, 다대일) 역할을 하는 테이블을 만들 수 있다는 점인데, 일반적으로 이 테이블 또한 여러 가지 방법으로 사용할 수 있다.
- 고객과 상품은 다대다 관계이다.
- 고객이 상품을 주문하고 그것을 비즈니스 로직으로 처리할 땐 주문정보 라는 테이블(엔티티)이 자연스럽게 필요하다.
- 주문정보 테이블엔 어떤 고객이 어떤 상품을 주문했는지 뿐만 아니라 몇 개 주문했고 가격은 얼마인지 등 다른 데이터 또한 들어갈 수 있다.
- RDB 관점에서도 다대다 JOIN은 없기 때문에 중간 테이블을 분리한다.
중간 테이블 사용하기
@Entity
@Data
@IdClass(MemberProductId.class)
public class MemberProduct {
@Id
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@Id
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
@Column
private int orderAmount;
}
// 다대다 관계를 맵핑하기 위한 중간 테이블의 복합키 클래스
// 이것을 DB 용어로 식별 관계라고 한다.
@Data
public class MemberProductId implements Serializable {
private String member;
private String product;
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
@Override
public int hashCode() {
return Objects.hash(member, product);
}
}
- 다대다 관계를 맵핑하기 위해 회원에 대해선 일대다, 상품에 대해선 다대일 관계를 가지는 MemberProduct라는 중간 테이블을 만들었다.
- 중간 테이블의 PK는 양쪽 테이블의 PK를 더한 복합 키이다.
- 이 복합 키를 관리하는 Class를 따로 만들고 equals, hashcode, 직렬화 구현 등을 다 해줘서 다대다 맵핑을 관리하는 방법이 있다.
- 이렇게 부모 테이블의 기본키를 받아서 자식 테이블의 기본키 + 왜래 키로 사용하는 것을 식별 관계라고 한다.
- 굉장히 복잡하다
- 그래서 이렇게 복합키로 중간 테이블을 관리하지 말고, 그냥 중간 테이블에 아무런 비즈니스적 의미가 없는 연속된 숫자를 키로 사용하면 편리하다.
- 이런 방법을 비식별 관계라고 한다.
- 많은 JPA 코드에서 Entity 클래스가 아무런 이유 없이 "private Long id" 를 가지는 것이 아닌 걸 알 수 있다.
'Programming' 카테고리의 다른 글
@cache (0) | 2021.06.28 |
---|---|
Flask 사용법 (2) | 2021.05.17 |
JPA Study 02 (0) | 2021.05.15 |
JPA Study 01 (0) | 2021.05.15 |
DB 예약어(MySQL, MariaDB) (0) | 2021.05.14 |