교재: 자바 ORM 표준 JPA 프로그래밍
7장에서 다룰 고급 매핑은 다음과 같다:
객체지향에서는 상속 구조를 사용하지만 데이터베이스는 테이블 구조를 사용한다. 그래서 JPA에서는 상속 구조를 테이블로 변환하는 전략이 필요하다.
대표적으로 3가지 전략이 있다.
부모와 자식 각각 테이블을 만든다. 자식 테이블은 부모의 PK를 FK로 같이 사용한다. 조회 시에는 JOIN이 필요하다.
장점
단점
핵심 설정
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
모든 데이터를 하나의 테이블에 저장한다. DTYPE 컬럼으로 타입을 구분한다.
장점
단점
핵심 설정
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
자식 엔티티마다 테이블을 만든다. 각 테이블에 부모 필드까지 모두 포함된다.
장점
단점
핵심 설정
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@MappedSuperclass는 테이블과 매핑되지 않는 부모 클래스이다. 단순히 공통 필드를 자식 엔티티에 상속하기 위한 용도이다. 데이터베이스에는 테이블이 생성되지 않는다.
부모 클래스는 @MappedSuperclass로 선언한다.
자식 클래스만 @Entity로 테이블과 매핑된다.
@MappedSuperclass
public abstract class BaseEntity {
@Id @GeneratedValue
private Long id;
private String name;
}
@Entity
public class Member extends BaseEntity {
private String email;
}
@Entity
public class Seller extends BaseEntity {
private String shopName;
}
특징:
주의점:
→ 정리: @MappedSuperclass는 테이블 매핑이 아닌 공통 필드 상속용 구조이다.
테이블 관계는 외래 키가 기본 키에 포함되는지에 따라 나뉜다.
복합 키는 2개 이상의 컬럼으로 구성된 PK이다. JPA에서는 단순히 @Id 여러 개로 처리할 수 없다 →식별자 클래스를 만들어야 한다.
JPA는 두 가지 방법을 제공한다.
@IdClass
DB 중심 방식이다. 엔티티에 여러 @Id를 직접 선언한다.
@IdClass(ParentId.class)
class Parent {
@Id String id1;
@Id String id2;
}
@EmbeddedId
객체지향 방식이다. 식별자 클래스를 엔티티 안에 포함한다.
@EmbeddedId
private ParentId id;
ex:
@IdClass로 식별 관계 매핑
식별 관계에서는 @Id + @ManyToOne을 같이 사용한다.
Child 엔티티 핵심
@Id
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
@Id
@Column(name = "CHILD_ID")
private String childId;
ChildId (식별자 클래스)
class ChildId {
private String parent; // Parent.id
private String childId;
}
GrandChild까지 확장
@Id
@ManyToOne
@JoinColumns({
@JoinColumn(name = "PARENT_ID"),
@JoinColumn(name = "CHILD_ID")
})
private Child child;
@Id
@Column(name = "GRANDCHILD_ID")
private String id;
@EmbeddedId + 식별 관계
이 경우는 @MapsId 사용이 핵심이다.
Child 엔티티
@EmbeddedId
private ChildId id;
@MapsId("parentId")
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
ChildId
@Embeddable
class ChildId {
private String parentId;
private String id;
}
GrandChild (EmbeddedId)
@EmbeddedId
private GrandChildId id;
@MapsId("childId")
@ManyToOne
@JoinColumns({
@JoinColumn(name = "PARENT_ID"),
@JoinColumn(name = "CHILD_ID")
})
private Child child;
구조 변화
Before (식별 관계)
After (비식별 관계)
@Id @GeneratedValue
private Long id;
@ManyToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
자식 PK = 부모 PK → 복합 키 필요 없음
@Entity
class BoardDetail {
@Id
private Long boardId;
@MapsId
@OneToOne
@JoinColumn(name="BOARD_ID")
private Board board;
}
식별 관계 단점
비식별 관계 장점
데이터베이스 테이블의 연관관계를 설계하는 방법은 크게 2가지다.
조인 컬럼 vs 조인 테이블
| 구분 | 조인 컬럼 | 조인 테이블 |
|---|---|---|
| 구조 | 단순 | 복잡 |
| 테이블 수 | 2개 | 3개 |
| null 처리 | 필요 | 불필요 |
| 확장성 | 낮음 | 높음 |
JPA 매핑
@ManyToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
@ManyToOne
@JoinTable(
name = "MEMBER_LOCKER",
joinColumns = @JoinColumn(name = "MEMBER_ID"),
inverseJoinColumns = @JoinColumn(name = "LOCKER_ID")
)
private Locker locker;
하나의 엔티티를 여러 테이블에 매핑할 수 있다.
@Entity
@Table(name = "BOARD")
@SecondaryTable(
name = "BOARD_DETAIL",
pkJoinColumns = @PrimaryKeyJoinColumn(name = "BOARD_DETAIL_ID")
)
public class Board {
@Id
private Long id;
private String title;
@Column(table = "BOARD_DETAIL")
private String content;
}
동작 방식:
BOARD → id, title
BOARD_DETAIL → content
기본 키로 조인
여러 테이블 매핑
@SecondaryTables({
@SecondaryTable(name="BOARD_DETAIL"),
@SecondaryTable(name="BOARD_FILE")
})