다대일 [N:1]
외래 키는 항상 다쪽에 있다. 따라서 객체 양방향 관계에서 연관관계의 주인은 항상 다쪽이다.
다대일: 양방향
양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
- JPA는 외래 키를 관리할 때 연관관계의 주인만 사용한다.
- 주인이 아닌 쪽은 조회를 위한 JPQL이나 객체 그래프를 탐색할 때 사용한다.
양방향 연관관계는 항상 서로를 참조해야 한다.
- 무한루프에 빠지지 않게 주의해야 한다.
일대다 [1:N]
자바 컬렉션인 Collection, List, Set, Map 중에 하나를 사용해야 한다.
일대다: 단방향
단점
- 매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다.
- 다른 테이블에 외래 키가 있으면 INSERT SQL에 추가로 연관관계 처리를 위한 UPDATE SQL을 실행해야 한다.
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자.
- 상황에 따라 다르겠지만 일대다 단방향 매핑보다는 다대일 양방향 매핑을 권장한다.
일대다: 양방향
일대다 양방향 매핑이라기보다는 일대다 단방향 매핑 반대편에 다대일 단방향 매핑을 읽기 전용으로 추가해서 일대다 양방향처럼 보이도록 하는 방법이다.
일대다 단방향 매핑이 가지는 단점을 그대로 가진다.
일대일 [1:1]
일대일 관계는 주 테이블이나 대상 테이블 중에 누가 외래 키를 가질지 선택해야 한다.
주 테이블에 외래 키
외래 키를 참조와 비슷하게 사용할 수 있어서 객체지향 개발자들이 선호한다.
주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.
대상 테이블에 외래 키
전통적인 데이터베이스 개발자들은 보통 대상 테이블에 외래 키를 두는 것을 선호한다.
테이블 관계를 일대일에서 일대다로 변경할 때 테이블 구조를 그대로 유지할 수 있다.
주의
프록시를 사용할 때 외래 키를 직접 관리하지 않는 일대일 관계는 지연 로딩으로 설정해도 즉시 로딩된다. (자세한 내용은 8장에서..)
다대다 [N:N]
관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다. 그래서 보통 다대다 관계를 일대다, 다대일 관계로 풀어내는 연결 테이블을 사용한다.
다대다: 단방향
...
@ManyToMany
@JoinTable(name = "MEMBER_PRODUCT",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name =
"PRODUCT_ID"))
private List<Product> products = new ArrayList<Product>();
- @JoinTable.name
- 연결 테이블을 지정한다.
- @JoinTable.joinColums
- 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정한다.
- @JoinTable.inverseJoinColumns
- 반대 방향인 상품과 매핑할 조인 컬럼 정보를 지정한다.
MEMBER_PRODUCT 테이블은 다대다 관계를 일대다, 다대일 관계로 풀어내기 위해 필요한 연결 테이블일 뿐이다.
다대다: 양방향
역방향도 @ManyToMany를 사용한다.
다대다: 매핑의 한계와 극복, 연결 엔티티 사용
연결 테이블에 컬럼을 추가하면 더는 @ManyToMany를 사용할 수 없다.
이럴 때는 다대다에서 일대다, 다대일 관계로 풀어야 한다.
회원상품 엔티티 코드
@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와 연결
...
}
회원상품 식별자 클래스
public class MemberProductId implements Serializable {
private String member; // MemberProduct.member와 연결
private String product; // MemberProduct.product와 연결
// hashCode and equals
@Override
...
}
- 이는 식별 관계다.
식별 관계
- 부모 테이블의 기본 키를 받아서 자신의 기본 키 + 외래 키로 사용하는 것을 데이터베이스 용어로 식별 관계라 한다.
회원상품 엔티티를 보면 기본 키를 매핑하는 @Id와 외래 키를 매핑하는 @JoinColumn을 동시에 사용해서 기본 키 + 외래 키를 한번에 매핑했다. 그리고 @IdClass를 사용해서 복합 기본 키를 매핑했다.
복합 기본 키
- 회원상품 엔티티는 기본 키가 MEMBER_ID와 PRODUCT_ID로 이루어진 복합 기본키다.
- JPA에서 복합 키를 사용하려면 별도의 식별자 클래스를 만들어야 한다. 그리고 엔티티에 @IdClass를 사용해서 식별자 클래스를 지정하면 된다.
- 복합 키를 위한 식별자 클래스의 특징
- Serializable을 구현해야 한다.
- equals와 hashCode 메소드를 구현해야 한다.
- 기본 생성자가 있어야 한다.
- 식별자 클래스는 public이어야 한다.
- @IdClass를 사용하는 방법 외에 @EmbeddedId를 사용하는 방법도 있다.
복합 키는 항상 식별자 클래스를 만들어야 한다.
복합 키를 사용하는 방법은 복잡하다.
다음으로 복합 키를 사용하지 않고 간단히 다대다 관계를 구성하는 방법을 알아보자.
다대다: 새로운 기본 키 사용 (비식별 관계)
추천하는 기본 키 생성 전략은 데이터베이스에서 자동으로 생성해주는 대리 키를 값으로 사용하는 것이다.
- 간편하고 거의 영구히 쓸 수 있으며 비즈니스에 의존하지 않는다.
- 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;
...
}
'JPA' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 프록시와 연관관계 관리 (0) | 2020.09.04 |
---|---|
[자바 ORM 표준 JPA 프로그래밍] 고급 매핑 (0) | 2020.09.04 |
[자바 ORM 표준 JPA 프로그래밍] 연관관계 매핑 기초 정리 (0) | 2020.03.12 |
[자바 ORM 표준 JPA 프로그래밍] 엔티티 매핑 정리 (0) | 2020.03.11 |
[자바 ORM 표준 JPA 프로그래밍] 영속성 관리 정리 (0) | 2020.03.10 |