繼承映射策略之----每個子類一張表
在每個子類一張表的映射策略中,每一個子類都有一張屬于自己的表,但是這張表只包括了定義在這個子類上面的屬性而已,定義在它的父類的屬性它的表里面是沒有的,所以這樣的方式映射的話,就不會浪費一點資源了,每一張表,每一列都是不可少的,也不會出現冗余。這種格式是有點像TABLE_PER_CLASS的策略,只不過這種方案是規范的,沒有像TABLE_PER_CLASS一樣重復定義列,在這里我們叫它JOINED策略。
按我們的例子,這種策略映射出來的話,數據庫的結構將如下所示:
create table Person (
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
);
create table Customer (
id integer primary key not null,
street varchar(255),
city varchar(255),
state varchar(255),
zip varchar(255),
);
create table Employee (
EMP_PK integer primary key not null,
employeeId integer
);
當持久化管理器加載一個類或者查詢一個子類的時候,它必須要對數據庫做連接動作,所以我們必須要保存這幾張表有一個能夠彼此連接起來的列。在我們的例子里面,EMPLOYEE, CUSTOMER, 和 PERSON表共享同樣的主鍵值,這種策略的注釋也是挺簡單的:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {

}
@Entity
public class Customer extends Person {

}
@Entity
@PrimaryKeyJoinColumn
(name="EMP_PK")
public class Employee extends Customer {

}
在持久化的時候,持久化管理器需要知道每一張表用哪一列來進行連接,所以當我們要指定某一列的時候,就可以用如下注釋:
@javax.persistence.PrimaryKeyJoinColumn,它的聲明如下:
package javax.persistence;
@Target({TYPE, METHOD, FIELD})
public @interface PrimaryKeyJoinColumn
String name( ) default "";
String referencedColumnName( ) default "";
String columnDefinition( ) default "";
}
name()方法提出你此表中需要用來連接的列的名字,它默認是與父類的主鍵進行連接,當我們不想與父類的主鍵進行連接時,我們可以用referencedColumnName( )這個方法來指定你要連接父類的哪個具體的列,它可以被定義為父類的任意列,但是默認是連接父類的主鍵列,如果從父類到子類的主鍵名都是一樣的,那么這個屬性就沒必要再設了,因為Customer和Person的主鍵是一樣的,所以在Customer里面不需要定義任何額外的屬性,一切默認就可以了,但是由于Employee里面的主鍵名和其它的不一樣,所以它必須顯式地聲明它的主鍵是哪一個。如果有的類有復合主鍵,那么可以用這個注釋:
@javax.persistence.PrimaryKeyJoinColumns
package javax.persistence;
@Target({TYPE, METHOD, FIELD})
public @interface PrimaryKeyJoinColumns {
@PrimaryKeyJoinColumn[] value( );
}
它包括了多個@PrimaryKeyJoinColumn的注釋。
注意:有些持久化實現這種策略會需要一個辨別器列,雖然大部份是不需要的,所以最好是在使用前查看一下你的持久化提供商的實現說明。
優點:
這種策略雖然沒有SINGLE_TABLE策略的速度快,但是你可以定義任何的非空約束在任何的表里面,并且這種模式是規范化的。
缺點:
唯一的缺點就是沒有SINGLE_TABLE 策略的性能好。
到現在我們三種處理繼承映射的策略都說完了,在不同的場合和環境下選擇不同的映射策略是最明智的選擇,沒有一種策略可以勝任所有場合,否則的話,出一種就可以了,干嘛還出三種呢。希望大家在實際工作中選出適合自己的映射策略,更好的提高工作效率。