7장. 상속 매핑

요약

7.1 암시적 다형성을 활용한 구체 클래스별 테이블 - @MappedSuperclass

Untitled

7.2 유니온을 활용한 구체 클래스별 테이블 - @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

Untitled

7.3 클래스 계층 구조별 테이블 - @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

Untitled

select bd from BillingDetails bd
---------
SELECT ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER,
	     ACCOUNT, BANKNAME, SWIFT, BD_TYPE
  FROM BILLINGDETAILS
select cc from CreditCard cc
---------
SELECT ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER
  FROM BILLINGDETAILS
 WHERE BD_TYPE = 'CC'

7.4 조인을 활용한 하위 클래스별 테이블 - @Inheritance(strategy = InheritanceType.JOINED), @PrimaryKeyJoinColumn, @DiscriminatorColumn

Untitled

select bd from BillingDetails bd
---------
SELECT BD.ID, BD.OWNER, 
			 CC.EXPMONTH, CC.EXPYEAR, CC.CARDNUMBER,
	     BA.ACCOUNT, BA.BANKNAME, BA.SWIFT, 
	     CASE
		     WHEN CC.CREDITCARD_ID is not null then 1
 		     WHEN BA.ID is not null then 2
 		     WHEN BD.ID is not null then 0
	     END
  FROM BILLINGDETAILS BD
  LEFT OUTER JOIN CREDITCARD CC ON CC.CREDIT_CARD = BD.ID
  LEFT OUTER JOIN BANKACCOUNT BA ON BA.ID = BD.ID
select cc from CreditCard cc
---------
SELECT CREDITCARD_ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER
  FROM CREDITCARD
 INNER JOIN BILLINGDETAILS BD ON BD.ID = CREDITCARD_ID

7.5 상속 전략 혼합 - @Inheritance(strategy = InheritanceType.SINGLE_TABLE), @DiscriminatorColumn, @SecondaryTable

Untitled

SELECT ID, OWNER, ACCOUNT, BANKNAME, SWIFT,
        EXPMONTH, EXPYEAR, CARDNUMBER,
	      BD_TYPE
  FROM BILLINGDETAILS
  LEFT OUTER JOIN CREDITCARD on ID = CREDIT_CARD_ID
select cc from CreditCard cc
---------
SELECT CREDITCARD_ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER
  FROM CREDITCARD
 INNER JOIN BILLINGDETAILS BD ON BD.ID = CREDITCARD_ID

7.1 암시적 다형성을 활용한 구체 클래스별 테이블 - @MappedSuperclass

Untitled

@MappedSuperclass
public abstract class BillingDetails { // 추상 클래스
	@Id
	@GeneratedValue(generator = "ID_GENERATOR")
	private Long id;

	@NotNull
	private String owner;
	
	// ...
}

@Entity
@AttributeOverride(
	name = "owner",
	column = @Column(name = "CC_OMNER", nulLable = false)
)
public class CreditCard extends BillingDetails {
	@NotNull
	private String cardNumber;

	@NotNull
	private String expMonth;

	@NotNull
	private String expYear;
	
	//...
}
@Entity
public class BankAccount extends BillingDetails {
	@NotNull
	private String account;
	
	@NotNull
	private String bankname;
	
	@NotNull
	private String swift;

	//...
}
@NoRepositoryBean
public interface BillingDetailsRepository<T extends BillingDetails, ID>
	extends JpaRepository<T, ID> {
	
	List<T> findByOwner(String owner);
}
public interface BankaccountRepository
		extends BillingDetailsRepository<BankAccount, Long> {
		
		List<BankAccount> findBySwift(String swift);
}
public interface CreditCardRepository
		extends BillingDetailsRepository<CreditCard, Long> {
		
		List<CreditCard> findByExpYear(String expYear);
}

7.2 유니온을 활용한 구체 클래스별 테이블 - @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public abstract class Billingbetails { // abstract
	@Id
	@GeneratedValue(generator = "ID_GENERATOR")
	private Long id;
	
	@NotNull
	private String owner;
	
	//...
}
@Entity 
@Attributeoverride(
	name = "owner",
	column = @Column(name = "CC_OWNER", nuLlable = false)
)
public class CreditCard extends BillingDetails {
	@NotNull
	private String cardNumber;
	
	@NotNull
	private String expMonth;
	
	@NotNull
	private String expYear;
	
	//...
}
@Entity
public class BankAccount extends BillingDetails {
	@NotNull
	private String account;
	
	@NotNull
	private String bankname;
	
	@NotNull
	private String swift;

	//...
}
public interface BillingDetailsRepository<T extends BillingDetails, ID>
	extends JpaRepository<T, ID> {
	
	List<T> findByOwner(String owner);
}
select bd from BillingDetails bd
---------
SELECT ID, OWNER, 
	     ACCOUNT, BANKNAME, SWIFT,
	     CARDNUMBER, EXPMONTH, EXPYEAR
FROM
(
	SELECT ID, OWNER, 
	       ACCOUNT, BANKNAME, SWIFT,
				 null as CARDNUMBER, null as EXPMONTH, null as EXPYEAR
	FROM BANKACCOUNT
	
	UNION ALL
	
	SELECT ID, OWNER, 
	       null as ACCOUNT, null as BANKNAME, null as SWIFT,
				 CARDNUMBER, EXPMONTH, EXPYEAR
	FROM CREDITCARD
) as BILLINGDETAILS

7.3 클래스 계층 구조별 테이블 - @Inheritance(strategy = InheritanceType.SINGLE_TABLE)

Untitled

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "BD_TYPE")
public abstract class BillingDetails {
	@Id
	@GeneratedVa lue(generator = "ID_GENERATOR")
	private Long id;
	
	@NotNull
	@Column(nulLable = false)
	private String owner;
	
	// ...
}
@Entity 
@DiscriminatorValue("CC")
public class CreditCard extends BillingDetails {
	@NotNull
	private String cardNumber;
	
	@NotNull
	private String expMonth;
	
	@NotNull
	private String expYear;
	
	//...
}
select bd from BillingDetails bd
---------
SELECT ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER,
	     ACCOUNT, BANKNAME, SWIFT, BD_TYPE
  FROM BILLINGDETAILS
select cc from CreditCard cc
---------
SELECT ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER
  FROM BILLINGDETAILS
 WHERE BD_TYPE = 'CC'

레거시 스키마여서 엔티티 테이블에 판별자 칼럼을 추가로 포함할 수 없는 경우 - @DiscriminatorFormula

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@org.hibernate.annotations.DiscriminatorFormula(
	"case when CARDNUMBER is not nult then 'CC' else 'BA' end"
)
public abstract class BillingDetails {
}

7.4 조인을 활용한 하위 클래스별 테이블 - @Inheritance(strategy = InheritanceType.JOINED), @PrimaryKeyJoinColumn, @DiscriminatorColumn

Untitled

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public abstract class BillingDetails {
	@Id
	@GeneratedVa lue(generator = "ID_GENERATOR")
	private Long id;
	
	@NotNull
	@Column(nulLable = false)
	private String owner;
	
	// ...
}
@Entity
// @PrimaryKeyJoinColumn(name = "BANKACCOUNT_ID") // 식별자를 상위 클래스로부터 상속
public class BankAccount extends BillingDetails {
	@NotNull
	private String account;
	
	@NotNull
	private String bankname;
	
	@NotNull
	private String swift;

	//...
}
@Entity 
@PrimaryKeyJoinColumn(name = "CREDITCARD_ID") // 식별자를 명시적으로 지정
public class CreditCard extends BillingDetails {
	@NotNull
	private String cardNumber;
	
	@NotNull
	private String expMonth;
	
	@NotNull
	private String expYear;
	
	//...
}
select bd from BillingDetails bd
---------
SELECT BD.ID, BD.OWNER, 
			 CC.EXPMONTH, CC.EXPYEAR, CC.CARDNUMBER,
	     BA.ACCOUNT, BA.BANKNAME, BA.SWIFT, 
	     CASE
		     WHEN CC.CREDITCARD_ID is not null then 1
 		     WHEN BA.ID is not null then 2
 		     WHEN BD.ID is not null then 0
	     END
  FROM BILLINGDETAILS BD
  LEFT OUTER JOIN CREDITCARD CC ON CC.CREDIT_CARD = BD.ID
  LEFT OUTER JOIN BANKACCOUNT BA ON BA.ID = BD.ID
select cc from CreditCard cc
---------
SELECT CREDITCARD_ID, OWNER, EXPMONTH, EXPYEAR, CARDNUMBER
  FROM CREDITCARD
 INNER JOIN BILLINGDETAILS ON BD.ID = CREDITCARD_ID

7.5 상속 전략 혼합 - @Inheritance(strategy = InheritanceType.SINGLE_TABLE), @DiscriminatorColumn, @SecondaryTable

Untitled

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "BD_TYPE")
public abstract class BillingDetails {
	@Id
	@GeneratedVa lue(generator = "ID_GENERATOR")
	private Long id;
	
	@NotNull
	@Column(nulLable = false)
	private String owner;
	
	// ...
}
@Entity 
@DiscriminatorValue("CC")
@SecondaryTable(
	name = "CREDITCARD"
	pkJoinColumns = @PrimaryKeyJoinColumn(name = "CREDITCARD_ID")
)
public class CreditCard extends BillingDetails {
	@NotNull
	private String cardNumber;
	
	@NotNull
	private String expMonth;
	
	@NotNull
	private String expYear;
	
	//...
}
SELECT ID, OWNER, ACCOUNT, BANKNAME, SWIFT,
        EXPMONTH, EXPYEAR, CARDNUMBER,
	      BD_TYPE
  FROM BILLINGDETAILS
  LEFT OUTER JOIN CREDITCARD on ID = CREDIT_CARD_ID

7.6 임베드 가능한 클래스의 상속

Untitled

@MappedSuperclass
public abstract class Measurement {
	@NotNull
	private String name;
	
	@NotNull
	private String symbol;
	
	// ...
}
@Embeddable
@AttributeOverride(name = "name", column = @Column(name = "DIMENSIONS_NAME"))
@AttributeOverride(name = "symbol", column = @Column(name = "DIMENSIONS_SYMBOL"))
public class Dimensions extends Measurement {
	@NotNull
	private BigDecimal depth;
	
	@NotNull
	private BigDecimal height;
	
	@NotNull
	private BigDecimal width;
	
	//...
}
@Embeddable
@AttributeOverride(name = "name", column = @Column(name = "WEIGHT_NAME"))
@AttributeOverride(name = "symbol", column = @Column(name = "WEIGHT_SYMBOL"))
public class Weight extends Measurement {
	@NotNull
	@Column(name = "WEIGHT")
	private BigDecimal value;

	// ...
}

@Entity
public class Item {
	
	private Dimensions dimensions;
	
	private Weight weight;

	// ...
}

7.7 전략 선택