sql로 연관 테이블을 만들어본 사람들은 다대다 테이블을 구현하기 위해 중간테이블을 하나 만드는 것을 알고 있을 것이다.
이때 생기는 중간테이블의 기본키는 다대다 A와 B클래스의 기본키를 합친 복합키로 설정된다.
글로 이해하기 어려우면 하단 사진을 참고하자.
JPA에서 복합키를 설정하는 방법부터 알아보자. 위 그림 그대로 구현한다.
먼저 다 쪽인 Member_Product가 연관간계의 주인이 되므로 Member와 Product는 mappedBy만 써주면 된다.(양방향 기준)
@Entity
public class Member {
...
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts = new ArrayList<MemberProduct>();
...
}
@Entity
public class Product {
...
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProducts = new ArrayList<MemberProduct>();
...
}
이제 중요한 Member_Product테이블은 IdClass 어노테이션을 통해 기본키를 설정한 클래스를 지정해줘야 한다.
이때 지정된 클래스는 Serializable을 구현한 클래스여야 한다.
package hellojpa;
import java.io.Serializable;
public class MemberProductId implements Serializable {
private String member; // MemberProduct.member와 매핑
private String product; // MemberProduct.product와 매핑
@Override
public int hashCode() {
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
실제로 생성되는 MemberProduct는 @IdClass를 지정했다면 다른 관계의 매핑과 똑같이 적용해주면 된다.
package hellojpa;
import javax.persistence.*;
@Entity
@IdClass(MemberProductId.class)
public class MemberProduct {
@Id
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@Id
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
private int amount;
public void setMember(Member member) {
this.member = member;
}
public void setProduct(Product product) {
this.product = product;
}
public void setAmount(int amount) {
this.amount = amount;
}
}
다음 코드를 통해 제대로 생성됐는지 확인해보자
Member member = new Member();
member.setId("member1");
member.setName("회원1");
em.persist(member);
Product product = new Product();
product.setId("productA");
product.setName("상품A");
em.persist(product);
MemberProduct memberProduct = new MemberProduct();
memberProduct.setMember(member);
memberProduct.setProduct(product);
memberProduct.setAmount(2);
em.persist(memberProduct);
복합키를 생성하여 매핑하는 것은 다른 관계보다 더 복잡하고 처리할 일이 상당히 많아진다.
따라서 복합키를 통한 관리는 추천하지 않고 데이터베이스에서 자동으로 생성해주는 대리 키를 Long 값으로 사용하는 것이 훨씬 효율적이다
장점으로 더욱 간편하고 거의 영구히 사용하며 비즈니스에 의존하지 않는다.
사용 방법은 간단하다 MemberProduct의 기본키를 @GeneratedValue를 통한 대리키로 설정해주면 된다.
@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;
}
위에서 사용한 테스트 코드를 그대로 다시 실행해보았다.
기존과는 다르게 MEMBERPRODUCT에 ID값이 추가되어 각 튜플마다 고유한 키값 하나로 구분된다.
'Study > JPA' 카테고리의 다른 글
[JPA] 프록시와 연관관계 (0) | 2023.09.08 |
---|---|
[객체지향쿼리] JPQL, Criteria, 네이티브 SQL, QueryDSL, JDBC Connection (0) | 2023.08.29 |
[JPA] 상속 관계 매핑과 @MappedSuperClass (0) | 2023.08.26 |
[JPA] 연관 관계의 주인과 양방향 연관 관계의 주의점 (0) | 2023.08.26 |
JPA, JPQL 이란? (1) | 2023.08.24 |