具有ORM中繼資料的領域對象稱為實體(Entity),按JPA的規範,實體具備以下的條件:
- 必須使用javax.persistence.Entity註解或者在XML對應檔中有對應的元素;
- 必須具有一個不帶參的建構函式,類不能聲明為final,方法和需要持久化的屬性也不能聲明為final;
- 如果游離狀的實體物件需要以值的方式進行傳遞,如通Session bean的遠程業務介面傳遞,則必須實現Serializable介面;
- 需要持久化的屬性,其存取修飾詞不能是public,它們必須通過實體類方法進行訪問。
- @Entity:將領域對象標註為一個實體,表示需要儲存到資料庫中,預設情況下類名即為表名,通過name屬性顯式指定表名,如①處的name = "T_TOPIC",表示Topic儲存到T_TOPIC表中;
- @Id :對應的屬性是表的主鍵,如②-1所示;
- @GeneratedValue:主鍵的產生策略,通過strategy屬性指定。預設情況下,JPA自動選擇一個最適合底層資料庫的主鍵建置原則,如SqlServer對應identity,MySql對應auto increment。在javax.persistence.GenerationType中定義了以下幾種可供選擇的策略:
- IDENTITY:表自增鍵欄位,Oracle不支援這種方式;
- AUTO: JPA自動選擇合適的策略,是預設選項;
- SEQUENCE:通過序列產生主鍵,通過@SequenceGenerator註解指定序列名,MySql不支援這種方式;
- TABLE:通過表產生主鍵,架構藉由表類比序列產生主鍵,使用該策略可以使應用更易於資料庫移植。不同的JPA實現商產生的表名是不同的,如OpenJPA產生openjpa_sequence_table表Hibernate產生一個hibernate_sequences表,而TopLink則產生sequence表。這些表都具有一個序列名和對應值兩個欄位,如SEQ_NAME和SEQ_COUNT。
- @Column(name = "TOPIC_ID"):屬性對應的表欄位。我們並不需要指定表欄位的類型,因為JPA會根據反射從實體屬性中擷取類型;如果是字串類型,我們可以指定欄位長度,以便可以自動產生DDL語句,如③處所示;
- @Temporal(TemporalType.DATE):如果屬性是時間類型,因為資料表對時間類型有更嚴格的劃分,所以必須指定具體時間類型。在javax.persistence.TemporalType枚舉中定義了3種時間類型:
- DATE :等於java.sql.Date
- TIME :等於java.sql.Time
- TIMESTAMP :等於java.sql.Timestamp
對於繼承的實體,在javax.persistence.InheritanceType定義了3種映射策略,:
- SINGLE_TABLE:父子類都儲存到同一個表中,通過欄位值進行區分。這是我們Topic實體所採用的策略,Topic和PollTopic都儲存到同一張表中,通過TOPIC_TYPE欄位進行區分,Topic在T_TOPIC表中對應TOPIC_TYPE=1的記錄,而PollTopic對應 TOPIC_TYPE=2的記錄(稍後在PollTopic實體中指定);區別的欄位通過@DiscriminatorColumn說明,區分欄位對應該實體的值通過@DiscriminatorValue指定;
- JOINED:父子類相同的部分儲存在同一個表中,不同的部分分開存放,通過表串連擷取完整資料;
- TABLE_PER_CLASS:每一個類對應自己的表,一般不推薦採用這種方式。