흰 스타렉스에서 내가 내리지

[JPA] 연관관계 - 다대다 @ManyToMany, 복합 키, 식별자 클래스, @IdClass 본문

Spring

[JPA] 연관관계 - 다대다 @ManyToMany, 복합 키, 식별자 클래스, @IdClass

주씨. 2023. 2. 10. 22:46
728x90

@ManyToMany 이용

@Entity
@Getter @Setter
public class Member{
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    private String username;

    @ManyToMany
    @JoinTable(name = "MEMBER_PRODUCT",
            joinColumns = @JoinColumn(name = "MEMBER_ID"),
            inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID"))
    private List<Product> products = new ArrayList<Product>();
 }
 
@Entity
public class Product {
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;

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

}

 

@ManyToMany를 사용하면 MEMBER_PRODUCT 연결 테이블을 자동으로 처리해준다.

도메인 모델이 단순해지고 편리해진다.

 

하지만, 연결 테이블에 보통 단순히 양쪽의 아이디만 담고 끝나지 않는다.

주문 수량컬럼이나 주문 날짜 컬럼이 더 필요하다.

이렇게 컬럼을 더 추가하려면 @ManyToMany는 사용할 수 없다.

 

따라서 연결 테이블을 매핑하는 연결 엔티티를 만들고 이곳에 추가한 컬럼들을 매핑해야 한다.

그리고 엔티티 간의 관계도 테이블 관계처럼 다대다에서 일대다, 다대일 관계로 풀어야 한다.

 

 

복합키 사용

@Entity
@Getter @Setter
public class Member{
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    // 역방향
    @OneToMany(mappedBy = "member")
    private List<MemberProduct> memberProducts;
}


@Entity
public class Product {
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;

    private String name;
}


public class MemberProductId implements Serializable {
    private Long member;    // MemberProduct.member와 연결
    private Long product;   // MemberProduct.product와 연결
	
    // equals()와 hashCode()는 IDE에서 자동생성 해주는 기능이 있음
    
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof MemberProductId)) return false;
        MemberProductId that = (MemberProductId) o;
        return Objects.equals(member, that.member) && Objects.equals(product, that.product);
    }

    @Override
    public int hashCode() {
        return Objects.hash(member, product);
    }
}


@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {
    @Id
    @ManyToOne
    @JoinColumn(name = "MEMBER_ID")
    private Member member;  //MemberProductId.member와 연결

    @Id
    @ManyToOne
    @JoinColumn(name = "PRODUCT_ID")
    private Product product;    //MemberProductId.product와 연결

    private int orderAmount;
}

MemberProduct 클래스를 보면, 기본 키를 매핑하는 @Id와 외래 키를 매핑하는 JoinColumn을 동시에 사용해서 기본 키 + 외래 키를 한 번에 매핑했다. 그리고 @IdClass를 사용해서 복합 기본 키를 매핑했다.

 

회원 상품 엔티티는 기본 키가 MEMBER_ID와 PRODUCT_ID로 이루어진 복합 기본키다.

JPA에서 복합 키를 사용하려면 별도의 식별자 클래스를 만들어야 한다. 

그리고 엔티티에 @IdClass를 사용해서 식별자 클래스를 지정하면 된다.

여기서는 MemberProductId 클래스를 복합 키를 위한 식별자 클래스로 사용한다.

 

식별자 클래스

- 복합 키는 별도의 식별자 클래스로 만들어야 한다.

- Serializable을 구현해야 한다.

- equals와 hashCode 메소드를 구현해야 한다.

- 기본 생성자가 있어야 한다.

- 식별자 클래스는 public 이어야 한다.

- @IdClass 를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.

 

 

다대다 : 새로운 기본 키 사용

@Entity
@Getter @Setter
public class Member{
    @Id @GeneratedValue
    @Column(name = "MEMBER_ID")
    private Long id;

    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<Order>();

    private String username;
}


@Entity
public class Product {
    @Id @GeneratedValue
    @Column(name = "PRODUCT_ID")
    private Long id;

    private String name;
}


@Entity
@Table(name = "Orders")
@Getter @Setter
public class Order {
    @Id @GeneratedValue
    private Long id;

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

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

    private int orderAmount;

}

식별자 클래스를 사용하지 않아서 코드가 한결 단순해졌다. 추천방식