본문 바로가기

스터디/JPA

다양한 연관관계 매핑 - (3)

728x90
반응형

다대다


 

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

-> 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다

 

객체는 테이블과 다르게 객체 2개로 다대다 관계를 만들 수 있다

-> 서로를 컬렉션을 이용해 참조하면 된다

다대다: 단방향

@Entity
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;
	
	private String name;
	...
}

@ManyToMany@JoinTable을 사용해 연결 테이블을 엔티티 없이 바로 매핑할 수 있다

 

@JoinTable 속성

  - name: 연결 테이블을 지정한다

  - joinColumns: 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정한다

  - inverseJoinColumns: 반대 방향인 상품과 매핑할 조인 컬럼 정보를 지정한다

 

회원을 저장할 때 연결 테이블에도 값이 저장된다

 

회원 엔티티를 통해 상품을 조회하면 member_product와 product 테이블을 조인해 연관된 상품을 조회한다

다대다: 양방향

@Entity
public class Product {
	
	@Id @GeneratedValue
	@Column(name="PRODUCT_ID")
	private Long id;
	
	private String name;
	
	@ManyToMany(mappedBy="products")
	private List<Member> members;
	...
}

역방향도 @ManyToMany를 사용하고 mappedBy를 사용해 연관관계의 주인을 지정한다

 

다른 양방향 연관관계와 동일하게 편의 메소드를 추가해 관리하는 것이 편리하다

다대다: 매핑의 한계 극복, 연결 엔티티 사용

@ManyToMany를 사용하면 연결 테이블을 자동으로 처리해주므로 편리하다

 

하지만 이를 실무에서 사용하기에는 한계가 존재한다

예로 들어 회원이 상품을 주문하면 연결 테이블에 단순히 회원 아이디와 상품 아이디만 담는 것이 아니라 주문 수량 컬럼이나 주문한 날짜 같은 컬럼이 추가적으로 필요하다

 

컬럼을 추가하면 더는 @ManyToMany를 사용할 수 없다

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

 

@Entity
public class Member {
	
	@Id @GeneratedValue
	@Column(name="MEMBER_ID")
	private Long id;
	
	private String username;
	
	@OneToMany(mappedBy="member")
	private List<MemberProduct> memberProducts;
	...
}
@Entity
public class Product {
	
	@Id @GeneratedValue
	@Column(name="PRODUCT_ID")
	private Long id;
	
	private String name;
	...
}
@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 orderAmount;
	...
}
public class MemberProductId implements Serializable {

	private String member;
	private String product;
	
	@Override
	public boolean equals(Object o) {...}
	
	@Override
	public int hashCode() {...}
}

기본 키를 매핑하는 @Id와 외래 키를 매핑하는 @JoinColumn을 한번에 매핑했다

@IdClass를 사용해 복합 기본 키를 매핑했다

 

 

복합 기본 키

 

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

JPA에서 복합 키를 사용하기 위해서는 별도의 식별자 클래스를 만들고, 엔티티에 @IdClass를 식별자 클래스를 지정해야 한다

 

 

복합 키를 위한 식별자 클래스 특징

 

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

  - Serializable을 구현해야 한다

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

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

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

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

     @EmbeddedId를 사용하면 식별자 클래스 자체를 기본 키로 사용한다

 

 

식별 관계

 

회원상품은 회원과 상품의 기본 키를 받아서 자신의 기본 키로 사용한다

부모 테이블의 기본 키를 받아 자신의 기본 키 및 외래 키로 사용하는 것식별 관계(Identifying Relationship)라고 한다

 

 

저장 시 회원상품 엔티티를 통해 회원과의 연관관계, 상품과의 연관관계를 설정해줘야 한다

  - 복합 키를 사용하는 경우, 조회 시 식별자 클래스를 만들어 엔티티를 조회해야 한다

  - 복합 키를 사용하는 경우 ORM 매핑에서 처리할 일이 상당히 많아진다

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

복합 키를 사용하는 대신 데이터베이스에서 자동으로 생성해주는 대리 키를 사용하는 것을 추천하는데 이를 비식별 관계라고 한다

간편하고 영구히 사용할 수 있으며 복합 키를 만들지 않아도 되므로 간단히 매핑할 수 있다

 

@Entity
public class Order {

	@Id @GeneratedValue
	@Column(name="ORDER_ID")
	private Long Id;
	
	@ManyToOne
	@JoinColumn(name="MEMBER_ID")
	private Member member;
	
	@ManyToOne
	@JoinColumn(name="PRODUCT_ID")
	private Product product;
	
	private int orderAmount;
	...
}

조회하는 코드에서 식별자 클래스를 사용하지 않아 코드가 간결해진다

이처럼 새로운 기본 키를 사용해 다대다 관계를 풀어내는 것도 좋은 방법이다

728x90
반응형

'스터디 > JPA' 카테고리의 다른 글

고급 매핑 - (2)  (0) 2025.02.12
고급 매핑 - (1)  (0) 2025.02.11
다양한 연관관계 매핑 - (2)  (0) 2025.02.10
다양한 연관관계 매핑 - (1)  (0) 2025.02.10
연관관계 매핑 기초 - (2)  (0) 2025.02.09