Table per subclass的繼承映射方式,給予父類與子類個分別的表格,而父類與子類對應的表格透過外鍵來產生關聯,具體的說,User類別、 Nobody類別與Somebody類別所映射的表格如下:
其中T_USER表格的id與Nobody及Somebody的id 一致,具體的說,在儲存Nobody實例時,id與name屬性記錄在T_USER表格中,而nobodyProp記錄在T_NOBODY中,假設T_USER表格的id值為1,則T_NOBODY表格對應的該筆記錄其id值也會為1。
而在定義時,可以標註InheritanceType為JOINED,例如:
- User.java
package onlyfun.caterpillar;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;
@Entity
@Table(name="T_USER")
@Inheritance(strategy=InheritanceType.JOINED)
public class User implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private Long age;
// 以下為 Getter、Setter
...
}
而子類別的部份,則使用@PrimaryKeyJoinColumn標註對應的主鍵欄位,例如:
- Nobody.java
package onlyfun.caterpillar;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
@Entity
@Table(name="T_NOBODY")
@PrimaryKeyJoinColumn(name="NOBODY_ID")
public class Nobody extends User {
private String nobodyProp;
// 以下為 Getter、Setter
...
}
- Somebody.java
package onlyfun.caterpillar;
import javax.persistence.Entity;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.Table;
@Entity
@Table(name="T_SOMEBODY")
@PrimaryKeyJoinColumn(name="SOMEBODY_ID")
public class Somebody extends User {
private String someBodyProp;
// 以下為 Getter、Setter
...
}
同樣記得,在persistence.xml中,要增加這三個類別的<class>標籤,以載入實體類別資訊。
假設您分別儲存了User、Nobody與Somebody實例,則一個MySQL資料庫中的表格狀態如下所示:
而在查詢時,會使用適當的JOIN來結合表格進行查詢,例如在Hibernate作為JPA的實作下,以下的查詢:
Query query = entityManager.createQuery("SELECT user FROM User user");
會產生以下的SQL語句:
select
user0_.id as id0_,
user0_.age as age0_,
user0_.name as name0_,
user0_1_.nobodyProp as nobodyProp1_,
user0_2_.someBodyProp as someBody1_2_,
case
when user0_1_.NOBODY_ID is not null then 1
when user0_2_.SOMEBODY_ID is not null then 2
when user0_.id is not null then 0
end as clazz_
from
T_USER user0_
left outer join
T_NOBODY user0_1_
on user0_.id=user0_1_.NOBODY_ID
left outer join
T_SOMEBODY user0_2_
on user0_.id=user0_2_.SOMEBODY_ID
而如果是查詢個別資料,例如:
Nobody nobody = entityManager.find(Nobody.class, new Long(1));
會產生以下的SQL語句:
select
nobody0_.NOBODY_ID as id0_0_,
nobody0_1_.age as age0_0_,
nobody0_1_.name as name0_0_,
nobody0_.nobodyProp as nobodyProp1_0_
from
T_NOBODY nobody0_
inner join
T_USER nobody0_1_
on nobody0_.NOBODY_ID=nobody0_1_.id
where
nobody0_.NOBODY_ID=?
效能是這個映射類型需要考量的,在複雜的類別繼承下,新增資料必須對多個表格進行,而查詢時,跨越多個表格的join也可能引發效能上的問題。
如果您需要多型查詢,而子類別相對來說有較多新增的屬性,則可以使用這種映射方式。