千里冰封
          JAVA 濃香四溢
          posts - 151,comments - 2801,trackbacks - 0

          單個實(shí)體BEAN的映射到數(shù)據(jù)庫的方式很簡單,但是如果我們的實(shí)體BEAN之間存在著繼承關(guān)系呢?在數(shù)據(jù)庫里面將如何表現(xiàn)這種繼承關(guān)系?
          JAVA持久化規(guī)范里面提供了三種方式去處理繼承實(shí)體的映射方式:
          一,所有繼承層次共單獨(dú)一張表
          二,每個具體的類一個單獨(dú)的表
          三,每個子類一張表

          為了更好的舉例說明,我們構(gòu)造出如下的繼承層次,以做為例子使用。


          我們今天先來看看第一種方式,那就是所有的繼承層次共單獨(dú)一張表。

          一,所有繼承層次共單獨(dú)一張表

          在這種模式中,一張數(shù)據(jù)庫的表里面將放入所有的繼承層次的類的屬性,在我們的例子中,我們的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(31not null
          );

           

          正是因為我們把所有繼承層次的實(shí)體都放在同一張表里面,所以我們需要一個來標(biāo)志具體類型的列,它指示當(dāng)前記錄是屬于哪個類的,這樣EntityManager好還原成相應(yīng)的實(shí)體BEAN而不致于出錯。我們還是先看看代碼是如何告訴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注釋就是用來聲明繼承的時候它的持久化策略的,它的聲明如下:
           

           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()方法定義了我們所使用的繼承映射模式,我們在這里用的是單獨(dú)一張表放所有的繼承層次實(shí)體,所以我們使用了枚舉InheritanceType.SINGLE_TABLE,有一點(diǎn)我們需要注意的是,@Inheritance這個注釋僅僅只在繼承層次的根類上是必須要有的,一般它的子類都沒有必要寫這個注釋,除非你想改變繼承映射的實(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;
          }

           

          因為我們使用一張表來保存所有繼承層次的類,所以我們需要一個某種方式好讓持久化實(shí)現(xiàn)者知道如何去分辨我們真正想要保存的對象是屬于哪個繼承層次的,我們靠從一個辨別器的列里面去獲得這一點(diǎn)。@javax.persistence.DiscriminatorColumn這個流釋就是指示我們哪個類將會存儲辨別器,看著注釋我們可以知道,這個注釋并不是必要的,因為它每項都有默認(rèn)值,對于辨別器的類型,默認(rèn)是String類型,我們除了String類型之外,還可以用如下幾個類型:char,Integer。

           

          package javax.persistence;

          @Target(TYPE) @Retention(RUNTIME)
          public @interface DiscriminatorValue {
             String value( )
          }

           

          這個注釋是指示我們辨別器的值是多少,這個只是我們提示辨別器的類型是String的時候,還需要我們?nèi)懀绻愋褪莍nt或者char的時候,是不需要我們?nèi)ヌ岫ㄋ鼈兊谋鎰e器的值的。所以最好還是使用char或者int類型,以使我們從這些細(xì)節(jié)方面解放出來。

          在我們建立了這種映射策略之后,子類的定義就顯得簡單多了:

           

          @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; }
          }

           

          在這個例子里面,Customer實(shí)體的辨別器列的值設(shè)為CUST,這是我們?nèi)藶樵O(shè)置的。當(dāng)然我們?nèi)绻辉O(shè)置的話,就像Employee,那么它的辨別器列的值就會被設(shè)為Employee, 因為它的類的名字就是Employee。

          優(yōu)點(diǎn):
          SINGLE_TABLE的映射策略是最簡單的實(shí)現(xiàn)并且性能來說,也是比其它兩個要高。因為它只有一張表需要去處理。持久化引擎不需要去做任何復(fù)雜的連接組合或者子查詢等等,因為所有的的數(shù)據(jù)都存在一張表里面
          缺點(diǎn):
          這種策略最大的一個缺點(diǎn)就是所有的有關(guān)子類的屬性的映射列都必須是nullable,因為你不可能讓一個類擁有所有的屬性,畢竟這些屬性是所有的類加起來的,所以你不能為你的類加上NOT NULL的約束。還有,因為所有子類的屬性列對于某些實(shí)體類來說都是沒有用的,所以SINGLE_TABLE 策略也是不符合規(guī)范的。


           




          盡管千里冰封
          依然擁有晴空

          你我共同品味JAVA的濃香.
          posted on 2007-10-08 00:11 千里冰封 閱讀(952) 評論(0)  編輯  收藏 所屬分類: JAVAEE
          主站蜘蛛池模板: 赫章县| 拜泉县| 兴仁县| 凤山市| 萨嘎县| 汨罗市| 德惠市| 灌阳县| 景东| 呼玛县| 古丈县| 资阳市| 象山县| 安陆市| 武鸣县| 凤翔县| 古丈县| 上犹县| 新沂市| 滦南县| 柯坪县| 兴义市| 开封市| 卢龙县| 新化县| 邵武市| 井冈山市| 屏东县| 益阳市| 额尔古纳市| 泊头市| 台北市| 金乡县| 苏尼特右旗| 义乌市| 永安市| 安阳县| 荣成市| 镇平县| 襄城县| 深圳市|