Persistence Mapping - Inheritance
본 페이지에서는 상속 관계에 참여하는 각 클래스에 대한 여러 매핑 방법에 대해 자세히 살펴보도록 하자.
Table per Class Hierarchy
상속 관계에 참여하는 모든 Parent, Child 클래스들을 모두 한 개의 테이블로 매핑하고, Child 클래스의 유형을 구분하기
위해 별도 Discriminator 칼럼을 추가로 정의하는 매핑 방법이다.

왼쪽 상단 그림은 클래스다이어그램으로 User 클래스를 상속받은 Guest, Member, Staff 클래스들이 존재한다.
그리고 왼쪽 하단 그림은 ERD로 User, Guest, Member, Staff 클래스를 TBL_USER라는 하나의 테이블로 매핑하고 있다.
이와 같은 매핑 관계를 Hibernate Mapping XML 파일에 정의하는 방법은 오른쪽 그림의 내용과 같다. 그림 내용에 대해
설명하자면, User 클래스 정보를 class 태그를 이용하여 정의하고, 하위에 discriminator 태그를 이용하여 Child 클래스의
유형을 구분하기 위해 별도로 필요한 Discriminator 칼럼이 추가 정의되어야 한다. 또한 하위에 subclass 태그를 이용하여
User 클래스를 상속하는 하위 클래스와 속성들에 대해 정의하는데 이 때 각 subclass에 대한 Discriminator 값 정의가 필요하다.
Table per Class Hierarchy 매핑의 장,단점에 대해 살펴보면 다음과 같다.
[장점]
- 별도 Join 처리가 필요하지 않아 쿼리문 작성이 용이
- 상속 관계 제어를 위한 overhead가 최소화
[단점]
- 특정 테이블을 기준으로 NOT NULL constraints를 정의할 수 없음
- 하위 클래스가 추가될 테이블 구조 변경 불가피
- 관리 대상이 되는 칼럼과 NULL 값을 가진 칼럼들의 개수 증가
- 해당 Domain의 성격과 무관하게 하위 클래스의 타입을 구분하기 위한 별도 칼럼 정의 필요
별도 Discriminator 칼럼을 만들지 않고자 하는 경우에는 다음과 같이 formula라는 속성을 이용할 수 있다.
특정 칼럼의 값에 대한 연산을 통해 Discriminator 값을 정의하는 경우로 아래의 예에서는 DEPT_ID의 값이 NOT NULL인
경우 Discriminator 값은 'STAFF'이므로 해당되는 객체는 Staff가 될 것이다.
<discriminator
formula="CASE WHEN DEPT_ID IS NOT NULL THEN 'STAFF'
…"
type="string"/>
Table per Subclass
상속 관계에 참여하는 모든 Parent, Child 클래스들을 각각의 테이블로 매핑시키되, 모든 하위 테이블들이 상위 클래스와
동일한 Primary Key를 공유하는 형태이다.

왼쪽 상단 그림은 클래스다이어그램으로 User 클래스를 상속받은 Guest, Member, Staff 클래스들이 존재한다.
그리고 왼쪽 하단 그림은 ERD로 상속 관계에 참여하는 모든 클래스를 TBL_USER, TBL_GUEST, TBL_MEMBER, TBL_STAFF라는
테이블로 매핑하고 있다.
이와 같은 매핑 관계를 Hibernate Mapping XML 파일에 정의하는 방법은 오른쪽 그림의 내용과 같다. 그림 내용에 대해
설명하자면, User 클래스 정보를 class 태그를 이용하여 정의하고, 하위에 joined-subclass 태그를 이용하여
User 클래스를 상속하는 하위 클래스와 속성들에 대해 정의하고 있다.
Table per Subclass 매핑의 장,단점에 대해 살펴보면 다음과 같다.
[장점]
- 객체 지향에 가장 근접한 Mapping이고 하위 클래스가 많은 속성 정보를 가진 경우 가장 자연스러운 Mapping 기법
- 특정 테이블을 기준으로 NOT NULL Constraints 지정 가능
- Hibernate을 사용할 경우, 하위 클래스 유형을 구분하기 위한 별도 Discriminator 칼럼 불필요
[단점]
- 테이블 조회시 각 테이블 간의 Join이 필요하여 계층 관계가 복잡할수록 성능 이슈 유발 가능
- Hibernate을 이용하지 않고 외부에서 직접 데이터가 추가될 경우 데이터의 정합성이 깨질 우려가 있음
※ 조회하고자 하는 특정 Child 클래스를 명시하지 않고 Parent 클래스를 통해 조회를 요청할 경우
(즉, Parent 클래스를 이용하여 Query를 수행시키는 경우), Hibernate은 실제 조회
대상 클래스를 알 수 없어 해당 클래스의 유형을 찾기 위해 상속 관계에 참여하는 모든 테이블들에 대해 Outer JOIN이 수행되므로
성능 저하를 유발할 수 있음에 유의해야 한다.
(* 특정 Child 클래스를 조회 대상으로 명시하였을 경우에는 Inner JOIN이 수행된다.)
Table per Concrete Class
상속 관계에 참여하는 모든 Concrete 클래스들을 각각 한 개의 테이블로 매핑하는 방법으로, 매핑되는 모든 테이블에 상위 클래스의
속성 정보가 반복 정의되어야 한다. Parent 클래스가 추상 클래스일 경우 별도 테이블 정의는 필요하지 않으며, abstract를
true로 정의해야 한다.

왼쪽 상단 그림은 클래스다이어그램으로 User 클래스를 상속받은 Guest, Member, Staff 클래스들이 존재한다.
그리고 왼쪽 하단 그림은 ERD로 TBL_GUEST, TBL_MEMBER, TBL_STAFF라는 테이블로 매핑하고 있다.
이와 같은 매핑 관계를 Hibernate Mapping XML 파일에 정의하는 방법은 오른쪽 그림의 내용과 같다. 그림 내용에 대해
설명하자면, User 클래스 정보를 class 태그를 이용하여 정의하고 User 클래스의 abstract 속성을 true로 정의하고 있다.
또한 하위에 union-subclass 태그를 이용하여 각 하위 클래스들과 속성들에 대해 정의하고 있다.
Table per Concrete Class 매핑의 장,단점에 대해 살펴보면 다음과 같다.
[장점]
- 특정 테이블을 기준으로 NOT NULL Constraints 지정 가능
- Polymorphic Query 가 필요하지 않은 경우에 사용 시 유용함(*
Polymorphic Query : 조회 대상이 되는 특정 클래스/인터페이스를
extends 또는 implements하는 모든 클래스에 대해 조회)
[단점]
- 데이터 조회시 UNION을 이용해야 하나, UNION은 모든 DB에서 지원되는 것은 아니므로 유의
- 상위 클래스가 가진 공통 정보가 각 테이블에 중복됨
- Hibernate을 이용하지 않고 외부에서 직접 데이터가 추가될 경우 데이터의 정합성이 깨질 우려가 있음