[JPA] 연관관계 - 다대다 @ManyToMany, 복합 키, 식별자 클래스, @IdClass
@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;
}
식별자 클래스를 사용하지 않아서 코드가 한결 단순해졌다. 추천방식