@MappedSuperclass
상위 클래스의 인스턴스 쿼리 시, 쿼리 n회(하위 클래스 개수만큼) 발생
select bd from BillingDetails bd
---------
SELECT ID, OWNER, ACCOUNT, BANKNAME, SWIFT
FROM BANKACCOUNT;
SELECT ID, OWNER, CARDNUMBER, EXPMONTH, EXPYEAR
FROM CREDITCARD;
다형적 연관관계를 처리할 수 없다.
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
테이블 구조는 7.1 @MappedSuperclass
와 동일함.
상위 클래스의 인스턴스 쿼리 시, union all 처리되어 쿼리 1회 발생
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
다형적 연관관계를 처리할 수 있다.
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
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'
@Inheritance(strategy = InheritanceType.JOINED)
, @PrimaryKeyJoinColumn
, @DiscriminatorColumn
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
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
, @DiscriminatorColumn
, @SecondaryTable
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
@MappedSuperclass
@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);
}
단점
상위 클래스에 대한 쿼리를 구체적인 각 하위 클래스에 대해 하나씩 여러 개의 SQL SELECT를 실행한다.
select bd from BillingDetails bd
---------
SELECT ID, OWNER, ACCOUNT, BANKNAME, SWIFT
FROM BANKACCOUNT;
SELECT ID, OWNER, CARDNUMBER, EXPMONTH, EXPYEAR
FROM CREDITCARD;
다형적 연관관계를 처리할 수 없다.
@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
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@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 {
}
@Inheritance(strategy = InheritanceType.JOINED)
, @PrimaryKeyJoinColumn
, @DiscriminatorColumn
@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
hibernate.discriminator.ignore_explicit_for_joined
를 활성화 하면 된다.@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
, @DiscriminatorColumn
, @SecondaryTable
@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
@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;
// ...
}