1、多個entity對應同一張表,用一個字段區分
@Entity
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "GRP_UNITINFO")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "GROUPFLG", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorOptions(force=true)
@DiscriminatorValue(value = "2")
public class Unitinfo extends BaseActiveEntity implements java.io.Serializable {
@Entity
@Table(name = "GRP_UNITINFO")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "GROUPFLG", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorOptions(force=true)
@DiscriminatorValue(value = "1")
public class Subgroup extends BaseActiveEntity implements java.io.Serializable{
@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
@Table(name = "GRP_UNITINFO")
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name = "GROUPFLG", discriminatorType = DiscriminatorType.STRING)
@DiscriminatorOptions(force=true)
@DiscriminatorValue(value = "0")
@DiscriminatorOptions(force=true)可以用@ForceDiscriminator(org.hibernate.annotations.<em>ForceDiscriminator</em>)代替
@DiscriminatorColumn和@DiscriminatorOptions(force=true)在使用時,大部分情況下應該一起使用纔不會出問題,但爲什麼Hibernate卻必須在使用時要指定@DiscriminatorOptions,而且@DiscriminatorOptions中force的默認值還是false呢?
當使用Discriminator應用於單表時,才需要使用@DiscriminatorOptions(force=true),應用於JOIN_TABLE時,不需要此註解
原文詳見:http://stackoverflow.com/questions/12199874/about-the-use-of-forcediscriminator-discriminatoroptionsforce-true
首先看一下最頂層的父類EmployeeEO,代碼如下所示。
EmployeeEO
@Entity
@Table(name = "tb_employee")
/**繼承映射策略*/
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
/**標識字段定義*/
@DiscriminatorColumn(
name="employee_type",discriminatorType=DiscriminatorType.STRING
)
/**該類的標識*/
@DiscriminatorValue("employee")
public class EmployeeEO implements Serializable {
private Integer id;
private String name;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
在最頂層的父類中,通常要做以下映射:
l 使用@Entity註釋,標識該類以及所有的子類都映射到指定的表中,如果不標註,也可使用默認值。
l 使用@Inheritance註釋,標識該類的子類繼承映射的方式,該註釋的定義如一下所示:
@Target({TYPE}) @Retention(RUNTIME)
public @interface Inheritance {
InheritanceType strategy() default SINGLE_TABLE;
}
其中,InheritanceType有三種類型,即7.4.2小節中講述的三種類型,三種類型定義爲常量,默認爲SINGLE_TABLE。
public enum InheritanceType
{ SINGLE_TABLE, JOINED, TABLE_PER_CLASS };
SINGLE_TABLE表示繼承關係的實體保存在一個表;JOINED表示每個實體子類保存在一個表;TABLE_PER_CLASS表示每個實體類保存在一個表。這裏使用的是第一種策略,所以定義的代碼如下所示:
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
l 使用@DiscriminatorColumn註釋,標識改繼承層次上所區別每個實體的類型字段。它的定義如以下所示:
@Target({TYPE}) @Retention(RUNTIME)
public @interface DiscriminatorColumn {
String name() default "DTYPE";
DiscriminatorType discriminatorType() default STRING;
String columnDefinition() default "";
int length() default 31;
}
其中,@DiscriminatorColumn在使用時要注意以下這些問題。
(1)@DiscriminatorColumn只能標註在頂層的類中,而不能標註在子類中。
(2)@DiscriminatorColumn只在繼承策略爲“SINGLE_TABLE”和“JOINED”時使用。
(3)name屬性表示所標識具體類型的字段名稱,默認爲“DTYPE”,例如本例中使用的是字段“employee_type”,所以定義如下。
@DiscriminatorColumn(name="employee_type")
(4)discriminatorType屬性表示標識值的類型,默認爲STRING字符串。它使用的枚舉類型如下所示。
public enum DiscriminatorType { STRING, CHAR, INTEGER };
也就是說,標識值可以爲String、Char或者Integer
(5)columnDefinition屬性表示生成字段的DDL語句,與@Column中的columnDefinition屬性類似。
(6)length屬性表示爲標識值的長度,默認爲31。該屬性只在使用DiscriminatorType. STRING時才需要設置。
l 使用@DiscriminatorValue註釋,標註該實體類所實體標識字段的值,它的定義如下:
@Target({TYPE}) @Retention(RUNTIME)
public @interface DiscriminatorValue {
String value();
}
value的值表示所該實體的標註值。例如,標識字段“employee_type”的值爲“employee”時可以認爲是EmployeeEO實體。代碼設置如下所示:
@DiscriminatorValue("employee")
<pre name="code" class="plain"> 2、在JPA中,實體繼承關係的映射策略共有三種:單表繼承策略(table per class)、Joined策略(table per subclass)和Table_PER_Class策略。
1.單表繼承策略
單表繼承策略,父類實體和子類實體共用一張數據庫表,在表中通過一列辨別字段來區別不同類別的實體。具體做法如下:
a.在父類實體的@Entity註解下添加如下的註解:
@Inheritance(Strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name=”辨別字段列名”)
@DiscriminatorValue(父類實體辨別字段列值)
b.在子類實體的@Entity註解下添加如下的註解:
@DiscriminatorValue(子類實體辨別字段列值)
在JPA中,實體繼承關係的映射策略共有三種:單表繼承策略(table per class)、Joined策略(table per subclass)和Table_PER_Class策略。
1.單表繼承策略
單表繼承策略,父類實體和子類實體共用一張數據庫表,在表中通過一列辨別字段來區別不同類別的實體。具體做法如下:
a.在父類實體的@Entity註解下添加如下的註解:
@Inheritance(Strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name=”辨別字段列名”)
@DiscriminatorValue(父類實體辨別字段列值)
b.在子類實體的@Entity註解下添加如下的註解:
@DiscriminatorValue(子類實體辨別字段列值)
定義了一個父類
@Entity@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
@Table(name = "WINDOW_FILE")
@DiscriminatorColumn(name = "DISCRIMINATOR", discriminatorType = DiscriminatorType.STRING, length = 30)
@DiscriminatorValue("WindowFile")
public class WindowFile {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
@Basic
@Column(name = "NAME")
private String name;
@Basic
@Column(name = "TYPE")
private String type;
@Basic
@Column(name = "DATE")
private Date date;
//省略get set
}
後定義2個子類
@Entity
@DiscriminatorValue("Folder")
public class Folder extends WindowFile {
@Basic
@Column(name = "FILE_COUNT")
private Integer fileCount;
//省略get set
}
@Entity
@DiscriminatorValue("Document")
public class Document extends WindowFile {
@Basic
@Column(name = "SIZE")
private String size;
//省略get set
}
以上通過列DISCRIMINATOR的不同,區分具體父子實體。
實際表結構如下:
WINDOW_FILE DISCRIMINATOR,ID,NAME,DATE,TYPE,SIZE,FILE_COUNT
當你使用WindowFile實體時,實際表的字段爲DISCRIMINATOR='WindowFile',SIZE與FILE_COUNT永遠是空
當使用Folder實體時,DISCRIMINATOR='Folder',SIZE永遠是空,FILE_COUNT爲實際值。
Document同理,與Folder類似。
2.Joined策略
父類實體和子類實體分別對應數據庫中不同的表,子類實體的表中只存在其擴展的特殊屬性,父類的公共屬性保存在父類實體映射表中。具體做法:
@Inheritance(Strategy=InheritanceType.JOINED)
子類實體不需要特殊說明。
@Entity@Table(name = "T_ANIMAL")@Inheritance(strategy = InheritanceType.JOINED)public class Animal { @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO) private Integer id; @Column(name = "NAME") private String name; @Column(name = "COLOR") private String color; //省略get set}
@Entity@Table(name = "T_BIRD")@PrimaryKeyJoinColumn(name = "BIRD_ID")public class Bird extends Animal { @Column(name = "SPEED") private String speed; //省略get set}
@Entity@Table(name = "T_DOG")@PrimaryKeyJoinColumn(name = "DOG_ID")public class Dog extends Animal { @Column(name = "LEGS") private Integer legs; //省略get set}
實際表結構如下:
T_ANIMAL ID,COLOR,NAME
T_BIRD SPEED,BIRD(既是外鍵,也是主鍵)
T_DOG LEGS,DOG_ID(既是外鍵,也是主鍵)
3.Table_PER_Class策略:
Table_PER_Class策略,父類實體和子類實體每個類分別對應一張數據庫中的表,子類表中保存所有屬性,包括從父類實體中繼承的屬性。具體做法:
只需在父類實體的@Entity註解下添加如下註解:
@Inheritance(Strategy=InheritanceType.TABLE_PER_CLASS)
@Entity@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)@Table(name = "T_VEHICLE")public class Vehicle { // 基類 @Id // @GeneratedValue @Column(name = "ID") private Integer id; @Column(name = "SPEED") private Integer speed;// 速度 //省略get set}
@Entity@Table(name = "T_CAR")public class Car extends Vehicle { @Column(name = "ENGINE") private String engine;// 發動機 //省略get set}
一旦使用這種策略就意味着你不能使用AUTO generator 和IDENTITY generator,即主鍵值不能採用數據庫自動生成。
實際表結構如下:
T_VEHICLE ID,SPEED
T_CAR ID,SPEED,ENGINE