1. 상속관계 매핑
많이 사용되는 상속관계 매핑에는 3가지 종류가 있다.
- 조인 전략
- 단일 테이블 전략
- 자식 테이블에게 매핑 정보만 제공
- 조인 전략
조인 전략은 엔티티 각각을 테이블로 만들고 자식 엔티티가 부모 엔티티의 기본키를 받아서 기본키 + 외래키로 이용하는 전략이다.
테이블을 조회할때, Join을 이용해 상속관계를 표현한다.
@Entity
@Inheritance(startegy = InheritanceType.JOINED)
@DiscriminatorColumn(name = "DTYPE")
public class Entity1{
@ID
@GeneratedValue
@Column(name = "ENTITY_1_ID")
private Long id;
}
@Entity
@DiscriminatorValue("E2")
public class Entity2 extends Entity1{
/*
...
*/
}
@Inheritance 는 상속관계에서 선택한 전략을 나타낸다.
위 코드에서는 조인 전략을 사용하고 있으므로, startegy = InteheritanceType.JOINED가 된다.
@DiscriminatorColumn 은 부모 클래스에서 구분 컬럼을 지정한다. 기본값은 DTYPE으로 생략해도 된다.
@DiscriminatorValue는 부모의 구분 컬럼에 저장할 구분 값을 나타낸다.
조인컬럼은 테이블이 정규화되고, 저장공간을 효율적으로 사용할 수 있지만, 조회시 JOIN이 많이 사용되므로 성능이 저하되고, 데이터 등록시 INSERT문을 항상 두번 이상 실행하는 단점이 있다.
- 단일 테이블 전략
단일 테이블 전략은 하나의 테이블에 모든(모든 자식 엔티티의) 필드를 저장하고, 구분 컬럼을 이용해 어떤 자식 데이터가 저장되어 있는지 구분한다.
@Entity
@Inheritance(startegy = InheritanceType.SINGLE_TABLE)
@DiscirminatorColumn(name = "DTYPE")
public class Entity1{
@Id
@GeneratedValue
@Column(name = "ENTITY_1_ID")
private Long id;
}
@Entity
@DiscriminatorValue("E2")
public class Entity2 extends Entity1{
/*
...
*/
}
단일 테이블전략에서는
@Inheritance 의 전략을 InheritanceType.SINGLE_TABLE로 설정한다.
단일 테이블전략은 일반적으로 JOIN문을 사용하지않으므로 가장 빠르다.
하지만, 하나의 테이블에 모든 필드를 저장하므로 테이블이 커질 수 있고, 상황에 따라서 조회 성능이 더 느릴 수 있다.
- 자식테이블에게 매핑 정보만 제공
앞서 본 두가지 전략과는 다르게 이 방법을 사용하면, 부모 테이블은 데이터베이스에 저장되지않고, 부모테이블을 상속받은 자식 테이블만 데이터 베이스에 저장된다.
@MappedSuperclass
public class DateBaseEntity{
@Column(name = "LAST_MODIFIED_DATE")
private LocalDate lastModifiedDate;
@Column(name = "CREATED_DATE")
private LocalDate createdDate;
}
@Entity
@AttributeOverrides({
@AttributeOverride(name = "lastModifiedDate", column = @Column(name = "LMD")),
@AttributeOverride(name = "createdDate", column = @Column(name = "CD"))
})
@Table(name = "ENTITY1")
public class Entity1 extends DateBaseEntity{
@ID
@GeneratedValue
@Column(name = "ENTITY_1_ID")
private Long id;
}
위 코드에서 Entity1은 DateBaseEntity의 필드를 모두 상속받는다. 실제로 실행해보면 Entity1에 DateBaseEntity의 칼럼들이 저장되어 있는것을 볼 수 있다.
@AttributeOverrides, @AttributeOverride는 상속받은 (@MappedSuperclass)안의 필드의 칼럼들을 재정의 할때 사용하며, 사용하지않을시 부모 클래스의 칼럼명 그대로 테이블에 저장된다.
2. 복합키와 식별 관계 매핑
JPA에서 두개 이상의 기본키를 사용하려면, 오류가 발생한다. 이 경우, @IdClass 혹은 @EmbeddeId와 같은 방법을 사용해야한다.
식별관계 매핑은 식별관계와 비식별 관계 로 나뉜다.
- 식별관계 : 식별 관계는 부모 테이블의 기본 키를 내려받아 자식테이블에서 기본키 + 외래키로 사용하는것을 말한다.
식별관계 매핑의 경우 자식 테이블의 컬럼 갯수가 계속해서 늘어난다는점, 구현이 까다롭다는점, 비즈니스적으로 의미없는 대리키를 사용하기 힘들다는점 때문에, 비 식별관계를 선호하며, 이 글에서는 비식별 관계에 대해서만 적도록 하겠다.
- 비식별 관계 : 비식별 관계는 부모 테이블의 기본 키를 받아서 자식 테이블의 외래키로만 사용한다.
또한, 비 식별관계는 필수적 비식별 관계와 선택적 비식별 관계로 나뉘는데, 각각, null값을 허용 여부를 뜻하며, null값을 허용하는 선택적 비식별 관계는 부모 테이블과 연관관계를 맺을지 말지 선택할 수 있다.
- 비식별 관계
- @IdClass
@Entity
@IdClass(TestIdClass.class)
public class Entity1{
@ID
@Column(name = "ID1")
private Long id1;
@ID
@Column(name = "ID2")
private Long id2;
}
@Entity
public class Entity2{
@Id
private Long id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "ID1"),
@JoinColumn(name = "ID2")
})
private Entity1 entity1;
}
public class TestIdClass implements Serializable{
private Long id1;
private Long id2;
public TestIdClass(){}
public TestIdClass(Long id1, Long id2){
this.id1 = id1;
this.id2 = id2;
}
@Override
public boolean equals(Object o){...}
@Override
public int hashCode(){...}
}
TestIdClass를 사용하기 위해선, 복합키의 대상이 되는 클래스가 Serializable, equals, hashCode를 구현해야하며, 기본 생성자가 있어야한다.
Entity2를 보면, 부모키가 복합키이므로, 자식키도 @JoinColumns를 이용해 복합키로 매핑된것을 볼 수 있다.
-@EmbeddedId
@IdClass는 엔티티에 복합키를 매핑했다면, @EmbeddedId는 필드에서 복합키를 그대로 사용한다.
@Entity
public class Entity1{
@EmbeddedId
private TestIdClass id;
/*...*/
}
@Embeddable
public class TestIdClass implements Serializable{
@Column(name = "ID1")
private String id1;
@Column(name = "ID2")
private String id2;
// @IdClass와 똑같다.
}
EmbeddedId 복합키 매핑 방식을 사용하기 위해선, 복합키가 될 대상 클래스에 @Embeddable 어노테이션이 붙어 있어야하며, IdClass와 마찬가지로, Serializable, hashCode, equals를 구현해야한다.
'JPA' 카테고리의 다른 글
[JPA] SpringDataJPA - OSIV (0) | 2021.12.05 |
---|---|
[JPA] 지연로딩과 영속성전이 (0) | 2021.10.23 |
[JPA] 연관관계 매핑 (0) | 2021.10.14 |
[JPA] 필드와 컬럼 매핑 (0) | 2021.10.12 |
[JPA] JPA 영속성 컨텍스트 (0) | 2021.10.11 |