📌 다대일
다대일 관계에서 외래 키는 항상 다쪽에 존재한다. 즉, 연관관계의 주인은 항상 다쪽이다.
1️⃣ 다대일 단방향 [N:1]
회원은 Member.team으로 팀 엔티티를 참조할 수 있지만 반대로는 참조할 수 없다.
2️⃣ 다대일 양방향 [N:1, 1:N]
다대일 양방향에서 핵심은 다음과 같다.
- 양방향은 외래 키가 있는 쪽이 연관관계의 주인이다.
- 양방향 관계는 항상 서로를 참조해야 한다.
📌 일대다
다대일 관계의 반대 방향이다. 보통 엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션을 사용한다.
1️⃣ 일대다 단방향 [1:N]
보통 자신이 매핑한 테이블의 외래 키를 관리하는데 Team.members로 회원 테이블의 TEAM_ID 외래 키를 관리한다.
이 경우 mappedBy 속성을 사용하지 않고 @JoinColumn을 명시해야 한다.
외래 키가 다른 테이블에 있어 연관관계 처리 시 UPDATE SQL을 추가로 실행해야 한다.
따라서, 일대다 단방향 매핑보다 다대일 양방향 매핑을 권장한다.
2️⃣ 일대다 양방향 [1:N, N:1]
사실 다대일 양방향, 일대다 양방향 매핑은 같은 말이다. 따라서 없는 표현이다.
📌 일대일 [1:1]
일대일 관계에서는 어느 곳에서도 외래 키를 가질 수 있다. 따라서 누가 외래 키를 가질지 선택해야 한다.
1️⃣ 주 테이블에 외래 키
객체 참조와 비슷하게 사용할 수 있다는 점에서 선호되는 방식이다.
🧷 단방향
@Entity
public class Member {
...
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker lcoker;
...
}
@Entity
public class Locker {
...
private String name;
}
🧷 양방향
@Entity
public class Member {
...
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
...
}
@Entity
public class Locker {
...
@OneToOne(mappedBy = "locker")
private Member member;
...
}
양방향이므로 Locker 엔티티에 mappedBy 속성을 사용해서 연관관계의 주인이 아니라고 설정했다.
2️⃣ 대상 테이블에 외래 키
전통적인 데이터베이스 개발자가 선호하는 방식이다. 일대다로 넘어가기 편리하다는 장점이 있다.
🧷 단방향 : 허용 ❌
🧷 양방향
@Entity
public class Member {
...
@OneToOne(mappedBy = "member")
private Locker locker;
}
@Entity
public class Locker {
...
@OneToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
}
📌 다대다 [N:N]
관계형 데이터베이스에서는 다대다 관계를 표현할 수 없다.
그래서 연결 테이블을 사용해서 일대다, 다대일 관계로 풀어서 표현한다.
반면에 객체는 다대다 관계를 만들 수 있다.
1️⃣ 다대다 : 단방향
@Entity
public class Member {
...
@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
@Column(name = "PRODUCT_ID")
private String id;
}
회원 엔티티와 상품 엔티티를 @ManyToMany와 @JoinTable로 바로 매핑했다.
@JoinTable의 속성은 다음과 같다.
- name : 연결 테이블 지정
- joinColumns : 조인 칼럼 정보를 지정
- inverseColumns : 반대편 조인 칼럼 정보를 지정
2️⃣ 다대다 : 양방향
@Entity
public class Product {
...
@ManyToMany(mappedBy = "products") // 역방향 추가
private List<Member> members;
}
다대다 매핑으로 역방향도 @ManyToMany를 사용한다. 연관관계의 주인이 아니므로 mappedBy 속성을 사용한다.
3️⃣ 다대다 : 매핑의 한계와 극복, 연결 엔티티 사용
@ManyToMany를 사용하면 편리하지만 실무에서 사용하기에는 한계가 존재한다.
한계를 보완하기 위해서 연결 엔티티를 추가해서 관리할 수 있다.
아래 코드를 보면 @Id와 @JoinColumn을 통해서 기본 키와 외래 키를 한 번에 매핑했다.
또한 @IdClass를 이용해서 복합 기본 키를 매핑했다.
@Entity
public class Member {
// 역방향
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts;
...
}
@Entity
public class 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; // MemberProductI.product와 연결
private int orderAmount;
}
복합 키를 사용하기 위해서는 별도의 식별자 클래스를 만들어야 한다.
회원상품 식별자 클래스와 특징은 다음과 같다.
public class MemberProductId implements Serializable {
private String member; // MemberProduct.member와 연결
private String product; // MemberProduct.product와 연결
// hashCode and equals
@Override
public boolean equals(Object o) {...}
@Override
public int hashCode() {...}
}
- 복합 키는 별도의 식별자 클래스로 만들어야 하고 Serializable로 구현해야 한다.
- equals와 hashCode 메서드를 구현해야 한다.
- 기본 생성자가 있어야 한다.
- 식별자 클래스는 public이다.
회원상품은 회원에서 기본 키를 받아서 자신의 기본 키로 사용함과 동시에 회원과의 관계를 위한 외래 키로 사용한다.
4️⃣ 다대다 : 새로운 기본 키 사용
데이터베이스에서 자동으로 생성해주는 대리 키를 사용하면 두 가지 장점이 있다.
- 간편하고 비지니스에 의존하지 않는다.
- ORM 매핑 시 복합 키를 만들 필요가 없다.
다음과 같이 대리 키를 사용하면 복합 키를 사용하는 것보다 매핑이 훨씬 단순하고 이해하기 쉬워진다.
@Entity
public class Order {
@Id
@Column(name = "ORDER_ID")
@GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
...
}
5️⃣ 다대다 연관관계 정리
다대다 관계를 일대다 다대일 관계로 풀어내기 위해 식별자를 어떻게 구성할지 선택해야 한다.
단순하고 편리하다는 점에서 비식별 관계를 사용하자.
- 식별 관계 : 받아온 식별자를 기본 키 + 외래 키로 사용
- 비식별 관계 : 받아온 식별자는 외래 키로만 사용하고 새로운 식별자를 추가
'개인 공부 > JPA (자바 ORM 표준 JPA 프로그래밍)' 카테고리의 다른 글
[자바 ORM 표준 JPA 프로그래밍] 고급 매핑 (7장) (0) | 2022.12.12 |
---|---|
자바 ORM 표준 JPA 프로그래밍 : 연관관계 매핑 기초 (5장) (0) | 2022.11.18 |
자바 ORM 표준 JPA 프로그래밍 : 엔티티 매핑 (4장) (1) | 2022.10.06 |
자바 ORM 표준 JPA 프로그래밍 : 영속성 관리 (3장) (0) | 2022.09.26 |
자바 ORM 표준 JPA 프로그래밍 : JPA 시작 (2장) (0) | 2022.09.15 |
댓글