본문 바로가기
JPA

JPA - 다양한 연관관계 매핑(4) : 다대다 [N : M]

by 왈레 2022. 4. 10.

다대다

• 관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.

• 연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야한다.

• 보면 두 개의 PK가 묶여있는걸 알 수 있다.

 

 

 

 객체는 컬렉션을 사용해서 객체 2개로 다대다 관계 가능

 

다대다 단방향

public class Member{
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT")
    private List<Product> products = new ArrayList<>();
}

 

 

다대다 양방향 

public class Member{
    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT")
    private List<Product> products = new ArrayList<>();
}
public class Product{
    @ManyToMany(mappedBy = "products");
    private List<Member> members = new ArrayList<>();
}

 

 

※참고로 @JoinTable은 다음과 같이 몇가지 더 추가해줘야한다.

@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT",
        joinColumns = @JoinColumn(name = "MEMBER_ID"), // 내가 조인하는 대상은 MEMBER_ID
        inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID") // 반대쪽이 조인하는 대상은 PRODUCT_ID
)
private List<Product> products = new ArrayList<>();

 

다대다 정리

@ManyToMany 사용

@JoinTable로 연결 테이블 지정

• 다대다 매핑: 단방향, 양방향 가능

 

 

다대다 매핑의 한계

• 편리해 보이지만 실무에서 절대 사용X

중간테이블이 숨겨져있기 때문에 쿼리를 예측할 없다.

중간테이블에 삽입할 pk 컬럼외에는 다른 컬럼을 추가할 없다.

  (주문시간, 수량 같은 데이터가 들어올 수 있음)

 

다대다 한계 극복

연결 테이블용 엔티티 추가 (연결 테이블을 엔티티로 승격)

• @ManyToMany -> @OneToMany <- @ManyToOne

 

 

※ 위의 설계도에서는 Member에서만 MemberProduct 리스트를 참조하지만, 밑의 클래스는 Product도 MemberProduct 리스트를 참조한다.

 

public class MemberProduct{
    ...
    
    @MnayToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;
    
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;
}
public class Member{
    ....
    
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts = new ArrayList<>();
}
public class Product{
    ...
    
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> memberProducts = new ArrayList<>();
}

 

저자의 추천 

• 전통적인 방식인 두 개의 PK를 묶는 것보단, 의미없는 값을 PK로 두고 FK를 두는게 낫다.

• JPA에서는 두 개의 PK를 묶을경우 Composite id를 만들어줘야하는게 귀찮기도 하고, 유연하지 못하다.

• 어플리케이션을 운영/유지보수 하다보면 비즈니스가 변화하거나 업데이트를 해줘야하는데 pk가 어디에 종속적이면

시스템을 유연하게 변경하기가 어려워진다.

 

결론 : id는 그냥 일관성있게 @GernerateValue 만 써라.

 

 

@JoinColumn

외래 키를 매핑할 때 사용

 

 

@ManyToOne - 주요속성

다대일 관계 매핑

※targetEntity는 몰라도 된다. (과거에 Generic이 없던 시절 필요했던 속성)

※@OneToMany는 mappedBy 속성이 있지만, @ManyToOne은 mappedBy 속성이 없다.

이 말은 @ManyToOne의경우 반드시 연관관계의 주인되어야한다는 뜻이다.

 

@OneToMany - 주요속성

다대일 관계 매핑

댓글