單個(gè)實(shí)體BEAN的映射到數(shù)據(jù)庫(kù)的方式很簡(jiǎn)單,但是如果我們的實(shí)體BEAN之間存在著繼承關(guān)系呢?在數(shù)據(jù)庫(kù)里面將如何表現(xiàn)這種繼承關(guān)系?
JAVA持久化規(guī)范里面提供了三種方式去處理繼承實(shí)體的映射方式:
一,所有繼承層次共單獨(dú)一張表
二,每個(gè)具體的類(lèi)一個(gè)單獨(dú)的表
三,每個(gè)子類(lèi)一張表
為了更好的舉例說(shuō)明,我們構(gòu)造出如下的繼承層次,以做為例子使用。

我們今天先來(lái)看看第一種方式,那就是所有的繼承層次共單獨(dú)一張表。
一,所有繼承層次共單獨(dú)一張表
在這種模式中,一張數(shù)據(jù)庫(kù)的表里面將放入所有的繼承層次的類(lèi)的屬性,在我們的例子中,我們的Person,Customer,Empolyee的實(shí)體都將映射在同一張表里面,表的結(jié)構(gòu)如下所示:
create table PERSON_HIERARCHY
(
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
street varchar(255),
city varchar(255),
state varchar(255),
zip varchar(255),
employeeId integer,
DISCRIMINATOR varchar(31) not null
);
正是因?yàn)槲覀儼阉欣^承層次的實(shí)體都放在同一張表里面,所以我們需要一個(gè)來(lái)標(biāo)志具體類(lèi)型的列,它指示當(dāng)前記錄是屬于哪個(gè)類(lèi)的,這樣EntityManager好還原成相應(yīng)的實(shí)體BEAN而不致于出錯(cuò)。我們還是先看看代碼是如何告訴EntityManager它的繼承實(shí)現(xiàn)方式的。
@Entity
@Table(name="PERSON_HIERARCHY")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DISCRIMINATOR",
discriminatorType=DiscriminatorType.STRING)
@DiscriminatorValue("PERSON")
public class Person {
private int id;
private String firstName;
private String lastName;
@Id @GeneratedValue
public int getId( ) { return id; }
public void setId(int id) { this.id = id; }
public String getFirstName( ) { return firstName; }
public void setFirstName(String first) { this.firstName = first; }
public String getLastName( ) { return lastName; }
public void setLastName(String last) { this.lastName = last; }
}
@javax.persistence.Inheritance注釋就是用來(lái)聲明繼承的時(shí)候它的持久化策略的,它的聲明如下:
package javax.persistence;
@Target(TYPE) @Retention(RUNTIME)
public @interface Inheritance {
InheritanceType strategy( ) default SINGLE_TABLE;
}
public enum InheritanceType {
SINGLE_TABLE, JOINED, TABLE_PER_CLASS
}
在這里,strategy()方法定義了我們所使用的繼承映射模式,我們?cè)谶@里用的是單獨(dú)一張表放所有的繼承層次實(shí)體,所以我們使用了枚舉InheritanceType.SINGLE_TABLE,有一點(diǎn)我們需要注意的是,@Inheritance這個(gè)注釋僅僅只在繼承層次的根類(lèi)上是必須要有的,一般它的子類(lèi)都沒(méi)有必要寫(xiě)這個(gè)注釋?zhuān)悄阆敫淖兝^承映射的實(shí)現(xiàn)方式。
package javax.persistence;
@Target(TYPE) @Retention(RUNTIME)
public @interface DiscriminatorColumn
String name( ) default "DTYPE";
DiscriminatorType discriminatorType( ) default STRING;
String columnDefinition( ) default "";
int length( ) default 10;
}
因?yàn)槲覀兪褂靡粡埍韥?lái)保存所有繼承層次的類(lèi),所以我們需要一個(gè)某種方式好讓持久化實(shí)現(xiàn)者知道如何去分辨我們真正想要保存的對(duì)象是屬于哪個(gè)繼承層次的,我們靠從一個(gè)辨別器的列里面去獲得這一點(diǎn)。@javax.persistence.DiscriminatorColumn這個(gè)流釋就是指示我們哪個(gè)類(lèi)將會(huì)存儲(chǔ)辨別器,看著注釋我們可以知道,這個(gè)注釋并不是必要的,因?yàn)樗宽?xiàng)都有默認(rèn)值,對(duì)于辨別器的類(lèi)型,默認(rèn)是String類(lèi)型,我們除了String類(lèi)型之外,還可以用如下幾個(gè)類(lèi)型:char,Integer。
package javax.persistence;
@Target(TYPE) @Retention(RUNTIME)
public @interface DiscriminatorValue {
String value( )
}
這個(gè)注釋是指示我們辨別器的值是多少,這個(gè)只是我們提示辨別器的類(lèi)型是String的時(shí)候,還需要我們?nèi)?xiě),如果類(lèi)型是int或者char的時(shí)候,是不需要我們?nèi)ヌ岫ㄋ鼈兊谋鎰e器的值的。所以最好還是使用char或者int類(lèi)型,以使我們從這些細(xì)節(jié)方面解放出來(lái)。
在我們建立了這種映射策略之后,子類(lèi)的定義就顯得簡(jiǎn)單多了:
@Entity
@DiscriminatorValue
("CUST")
public class Customer extends Person {
private String street;
private String city;
private String state;
private String zip;
public String getStreet( ) { return street; }
public void setStreet(String street) { this.street = street; }

}
我們也可以都用默認(rèn)的值,什么額外的注釋都不要加
@Entity
public class Employee extends Customer {
private int employeeId;
public int getEmployeeId( ) { return employeeId; }
public void setEmployeeId(int id) { employeeId = id; }
}
在這個(gè)例子里面,Customer實(shí)體的辨別器列的值設(shè)為CUST,這是我們?nèi)藶樵O(shè)置的。當(dāng)然我們?nèi)绻辉O(shè)置的話(huà),就像Employee,那么它的辨別器列的值就會(huì)被設(shè)為Employee, 因?yàn)樗念?lèi)的名字就是Employee。
優(yōu)點(diǎn):
SINGLE_TABLE的映射策略是最簡(jiǎn)單的實(shí)現(xiàn)并且性能來(lái)說(shuō),也是比其它兩個(gè)要高。因?yàn)樗挥幸粡埍硇枰ヌ幚怼3志没娌恍枰プ鋈魏螐?fù)雜的連接組合或者子查詢(xún)等等,因?yàn)樗械牡臄?shù)據(jù)都存在一張表里面
缺點(diǎn):
這種策略最大的一個(gè)缺點(diǎn)就是所有的有關(guān)子類(lèi)的屬性的映射列都必須是nullable,因?yàn)槟悴豢赡茏屢粋€(gè)類(lèi)擁有所有的屬性,畢竟這些屬性是所有的類(lèi)加起來(lái)的,所以你不能為你的類(lèi)加上NOT NULL的約束。還有,因?yàn)樗凶宇?lèi)的屬性列對(duì)于某些實(shí)體類(lèi)來(lái)說(shuō)都是沒(méi)有用的,所以SINGLE_TABLE 策略也是不符合規(guī)范的。
盡管千里冰封
依然擁有晴空
你我共同品味JAVA的濃香.
posted on 2007-10-08 00:11
千里冰封 閱讀(949)
評(píng)論(0) 編輯 收藏 所屬分類(lèi):
JAVAEE