[JPA] @ManyToMany

hyyyynjn·2021년 3월 26일
0
post-thumbnail
post-custom-banner
  • 친구목록 가져오기에서 하나의 유저와 연관된 다른 유저들의 정보를 참조하는 방법으로 @ManyToMany를 생각했다.

JPA 의 @ManyToMany

  • 실무에선 사용하지 않은 것을 추천한다고 한다.

  • RDB에서는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
    • 그대신, 연결 테이블(조인 테이블)을 중간에 추가하여 일대다, 다대일 관계를 이용해야한다.

객체에서의 다대다

  • ORM은 테이블에서 불가능한 부분을 객체에서 지원해줘야 한다.
    • 객체의 다대다 관계(위의 그림)와 테이블에서의 일대다, 다대일 관계(아래 그림)의 차이를 ORM이 연결해준다.
    • JPA에서 @ManyToMany 어노테이션을 사용하여 이를 연결하고, @JoinTable로 연결 테이블을 지정할 수 있다.

다대다 단방향

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

다대다 양방향

@Entity
public class Product {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToMany(mappedBy = "products")
    private List<Member> members = new ArrayList<>();
}

다대다 매핑의 한계

  • 편리해 보이지만 실무에서 사용하면 안된다.
    • 이유
      • 매핑 정보만 넣는 것이 가능하고, 추가 정보를 넣는 것 자체가 불가능하다
      • 중간 테이블(Member_Product table)이 숨겨져 있으므로 예상하지 못한 쿼리가 나간다.

다대다 매핑 한계의 극복

  1. 연결 테이블용 엔티티를 추가한다 -> 연결 테이블을 엔티티로 승격시킨다.
  2. @ManyToMany를 -> 각각 일대다, 다대일 관계로 맺어준다.
  • 다시 말하면, JPA가 @ManyToMany 어노테이션으로 만들어주는 숨겨진 매핑테이블의 존재를 바깥으로 꺼낸다.

코드

Member @OneToMany

  • Member 엔티티에서 @OneToMany 관계로 변경한다.
@Entity
public class Member {
    ...
        
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts = new ArrayList<>();
    ...
}

Product @OneToMany

  • Product 엔티티에서 @OneToMany 관계로 변경한다.
@Entity
public class Product {
    ...
    @OneToMany(mappedBy = "product")
    private List<MemberProduct> members = new ArrayList<>();
    
    ...
}

MemberProduct @ManyToOne 2번

  • 연결 테이블을 MemberProduct 엔티티로 승격시킨다.
  • 이 곳에서 @ManyToOne 매핑을 두개 한다. (연관 관계의 주인)
@Entity
@Getter
@Setter
public class MemberProduct {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @ManyToOne
    @JoinColumn(name = "member_id")
    private Member member;

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

결론

  • User 객체는 또다른 User 객체를 참조해야한다.
    • @ManyToMany가 아닌 @OneToMany가 맞는 설계방향이다.
    • 셀프 참조

post-custom-banner

0개의 댓글