객체 지향 언어에는 상속이라는 관계성이 존재하지만 관계형 데이터베이스에는 상속 개념 없다. 그렇다면 테이블에서 공통된 부분을 별도로 분리해서 사용하는 방법은 없을까?🤔
Extended ER모델
이라고도 불리는 슈퍼-서브 타입 데이터 모델
은 데이터의 공통점, 차이점 등의 특징을 고려하여 효과적으로 데이터 모델링을 할 수 있는 기법이다.
🧐 Extended ER모델...Extended...☝️🤓
공통의 부분은 슈퍼타입으로 모델링하고, 공통으로부터 상속 받아 다른 엔티티와 차이가 있는 속성은 서브타입으로 구분해 구성한다.
서브타입은 속성에 따라 배타적(exclusive), 포괄적(inclusive)서브 카테고리로 나눌 수 있다.
1. 배타적(exclusive) : 서브타입간에 교집합이 존재하지 않을 경우
2. 포괄적(inclusive) : 서브타입간에 교집합이 존재할 경우
업무의 모습을 정확하게 표현하고 물리적 데이터 모델로 변환할 때 선택의 폭을 넓힐 수 있는 장점이 있다.
해당 모델링 기법은 논리적 데이터 모델에서 이용되는 형태이고, 분석 단계에서 많이 사용된다. 물리적 데이터 모델 설계를 위해서는 슈퍼-서브 타입 데이터 모델
을 일정한 기준으로 변환해야 한다.
아래의 관계를 JPA를 이용해 객체에 적용하여 DB와 매핑할 수 있다.
strategy = InheritanceType.SINGLE_TABLE
: Rollup(Single-Type)strategy = InheritanceType.TABLE_PER_CLASS
: Rolldown(Plus-Type)InheritanceType.JOINED
: Identity(One-To-One Type)@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DisCriminatorColumn(name = "DTYPE")
public class Item {
@Id
@GeneratedValue
private Long id;
private String name;
private int price;
}
@Entity
@DiscriminatorValue("A")
public class Album extends Item {
...
}
@Entity
@DiscriminatorValue("M")
public class Movie extends Item {
...
}
@Entity
@DiscriminatorValue("B")
public class Book extends Item {
...
}
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
을 사용할 때, @Id
생성 전략을 IDENTITY나 AUTO로 할 경우, 에러가 발생하므로 반드시 TABLE로 변경해야 한다.not null
제약 조건을 사용할 수 있다.추천하지 않는 전략!
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Item {
@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
private String name;
private int price;
}
@Entity
public class Album extends Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 부모 클래스 컬럼
private String Name;
private int price;
...
}
@Entity
public class Movie extends Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 부모 클래스 컬럼
private String Name;
private int price;
...
}
@Entity
public class Book extends Item {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 부모 클래스 컬럼
private String Name;
private int price;
...
}
INSERT
문이 두번 실행된다.@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@DicriminatorColumn(name = "DTYPE")
public class Item {
@Id
@GeneratedValue
@Column (name = "ITEM_ID")
private Long id;
private String name;
private int price;
}
@Entity
@DicriminatorValue("A")
public class Album extends Item {
private String artist;
...
}
@Entity
@DicriminatorValue("M")
public class Movie extends Item {
private String director;
private String actor;
...
}
@Entity
@DiscriminatorValue("B")
@PrimaryKeyJoinColumn(name = "BOOK_ID")
public class Book extends Item {
private String author;
private String isbn;
}