在 EJB 1.x/2.x 時代,無法透過繼承將單一資料表拆分映射為多個實體 Bean。EJB3 引入 InheritanceType.SINGLE_TABLE 策略,配合 @DiscriminatorColumn 與 @DiscriminatorValue,即可輕鬆實現「一張表、多個實體」的對應。
t_accounts 表包含以下欄位:
account_id(主鍵)、balance(餘額)、account_type(判別欄位,C=活期、S=儲蓄)overdraft_limit(僅活期使用)、interest_rate(僅儲蓄使用)
@Entity
@Table(name = "t_accounts")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "account_type")
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "account_id")
protected String id;
protected float balance;
@Column(name = "account_type", insertable = false, updatable = false)
protected String type;
// Getter/Setter 略...
}
關鍵點:
@Inheritance(strategy = SINGLE_TABLE):所有子類別共用同一張表。@DiscriminatorColumn(name = "account_type"):指定判別欄位。insertable = false, updatable = false:判別欄位由容器自動維護,不可手動寫入,否則會拋出 MappingException。@Entity
@DiscriminatorValue("C")
public class CheckingAccount extends Account {
private double overdraftLimit;
// Getter/Setter 略...
}
@Entity
@DiscriminatorValue("S")
public class SavingsAccount extends Account {
private double interestRate;
// Getter/Setter 略...
}
子類別透過 @DiscriminatorValue 宣告各自對應的判別值,持久化時容器自動填入 account_type。
CheckingAccount ca = new CheckingAccount();
ca.setBalance(342);
ca.setOverdraftLimit(120);
em.persist(ca); // 自動設定 account_type = 'C'
SavingsAccount sa = new SavingsAccount();
sa.setBalance(200);
sa.setInterestRate(3.21);
em.persist(sa); // 自動設定 account_type = 'S'
適用於子類別差異較小、欄位數較少的場景。