Spring/Spring Data JPA

[자바 ORM 표준 JPA 프로그래밍] 7. 고급 매핑

noahkim_ 2023. 12. 28. 02:59

김영한 님의 "자바 ORM 표준 JPA 프로그래밍" 책을 정리한 포스팅 입니다.

 

1. 상속 관계 매핑

  • 데이터베이스의 슈퍼타입-서브타입 논리를 테이블로 구현

 

조인 전략

  • 엔티티 각각을 테이블로 생성 + 자식 테이블의 기본키를 기본키+외래키로 사용 (부모 테이블의 기본키 받기)
  • 테이블에 컬럼을 따로 추가해주기 (DTYPE: 구분 컬럼)
  • 테이블 정규화 O + 참조 무결성 제약 O (외래키)
  • 단점: 조회 쿼리 복잡 + 삽입 쿼리 두 번 실행

 

@Inheritance
  • 조인 전략 지정 (상속 매핑 시)
  • 부모 클래스에 작성

 

@DiscriminatorColumn
  • 구분 컬럼 지정 (부모클래스)
  • 자식 테이블 구분용
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item{

@Id @GeneratedValue
	@Column(name = "ITEM_ID")
	private Long id;
	
	private String name;
	private int price;
}

 

@DiscriminatorValue
  • 구분 칼럼 값 (자식 클래스)
@Entity
@DiscriminatorValue("A")
public class Album extends Item{
	private String artist;
	...
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item{
	private String director;
	private String actor;
	...
}

 

전략: 단일 테이블 

  • 테이블 하나만 사용 (모든 행 저장)
  • (자식 엔티티) 모든 매핑 컬럼 ->  nullable
  • 조인 X (-> 빠름) / 테이블 크기 큼
@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "DTYPE")
public abstract class Item{

@Id @GeneratedValue
	@Column(name = "ITEM_ID")
	private Long id;
	
	private String name;
	private int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item{
	private String artist;
	...
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item{
	private String director;
	private String actor;
	...
}

 

전략: 구현 클래스마다 테이블 생성

  • 자식 엔티티마다 테이블 셍상
  • not null 제약 조건 사용 가능
  • 조인 O (여러 테이블 조회 시, 성능 느림)
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item{

	@Id @GeneratedValue
	@Column(name = "ITEM_ID")
	private Long id;
	
	private String name;
	private int price;
}
@Entity
public class Album extends Item{
	private String artist;
	...
}
@Entity
public class Movie extends Item{
	private String director;
	private String actor;
	...
}

 

2. @MappedSuperclass

  • 상속받는 자식 클래스에 매핑정보 제공 (부모클래스 테이블 생성 X)

 

@MappedSuperclass
  • 부모클래스 지정 (상속할 매핑정보)
  • 엔티티 X (추상클래스)
@MappedSuperclass
public abstract class BaseEntity {
    @Id @GeneratedValue
    private Long id; 
    private String name;
}

 

@AttributeOverride
  • 연관관계 재정의 (부모로부터 상속) 
@Entity
@AttributeOverride(name="id", column=@Column(name="MEMBER_ID"))  // 부모에게 물려받은 매핑정보를 재정의하는 방법
public class Member extends BaseEntity {...}
@Entity
@AttributeOverrides({ // 둘 이상 재정의할 때 사용
    name = "id", column = @Column(name = "SELLER_ID")),
    name = "name", column = @Column(name = "SELLER_NAME"))
})
public class Seller extends BaseEntity {...}

 

3. 복합 키와 식별 관계 매핑

식별 관계 vs 비식별 관계

  • 외래키가 기본키에 포함 여부

 

식별 관계
  • 자식 테이블의 기본키를 기본키+외래키로 사용 (부모 테이블의 기본키 받기)

 

비식별 관계
  • 자식 테이블의 외래키로 사용 (부모 테이블의 기본키 받기)
  • 외래 키의 NULL 허용여부 (필수적 or 선택적)
    • 필수적 비식별 관계 : 외래 키 NULL 허용 X
    • 선택적 비식별 관계 : 외래 키 NULL 허용 O (연관관계를 맺을 지 선택 가능)

 

복합 키: 비식별 관계 매핑

@IdClass
  • 복합 기본 키가 정의된 식별자 클래스를 설정합니다.
  • 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 합니다.
@Entity
@IdClass(ParentId.class)
public class Parent {
    @Id
    @Column(name = "PARENT_ID1")
    private String id1; //Parentld.id1과연결

    @Id
    @Column(name = "PARENT_ID2")
    private String id2; //Parentld.id2와연결
}
public class ParentId implements Serializable {
    private String id1; //Parent.id1 매핑
    private String id2; //Parent.id2 매핑

    public ParentId() { }

    public ParentId(String id1, String id2) {
    this.id1 = id1;
    this.id2 = id2;
    }

    @Override
    public boolean equals(Object o) {...}
    @Override
    public int hashCode() {. ..}
}

 

 

자식 클래스를 추가할 경우
  • 부모 테이블의 기본 키 컬럼이 복합 키이므로 자식 테이블의 외래 키도 복합키 입니다.
  • 외래 키 매핑 시 여러 컬럼을 매핑해야 하므로 @JoinColumns를 사용합니다.
@Entity
public class Child {
    @Id
    private String id;

    @ManyToOne
    @JoinColumns({
        @JoinColumn(name = ”PARENT_ID1”, referencedColumnName = "PARENT_ID1"),      
        @JoinColumn(name = "PARENT_ID2", referencedColumnName = "PARENT_ID2")      
    })
    private Parent parent;
}

 

@Embeddable
  • 식별자 클래스를 정의합니다.
@Embeddable
public class ParentId implements Serializable {
    @Column(name = "PARENT_ID1")
    private String id1;

    @Coluinn (name = "PARENT_ID2")
    private String id2;

    //equals and hashCode 구현
}

 

@EmbeddedId
  • 매핑할 식별자 클래스를 지정합니다.
@Entity
public class Parent {
    @EmbeddedId
    private ParentId id;
    private String name;
}

 

5. 엔티티 하나에 여러 테이블 매핑

@SecondaryTable

  • 한 엔티티에 여러 테이블을 매핑할 수 있습니다.
name 매핑할 다른 테이블의 이름
pkJoinColumns 매핑할 다른 테이블의 기본 키 컬럼 속성
@Entity
@Table(name="BOARD")
@SecondaryTable(name = "BOARD_DETAIL",
	pkJoinColumns=@PrimaryKeyJoinColumn(name="BOARD_DETAIL_ID"))    
public class Board {
    @Id @GeneratedValue
    @Column(name="BOARD_ID")
    private Long id;
    private String title;
    
    @Column(table = "BOARD_DETAIL")
    private String content;
}