本文的主要內容如下:
詳細解釋了下面9個批注的含義及其批注所包含的屬性:
@MapKey
@MappedSuperclass
@NamedNativeQueries
@NamedNativeQuery
@NamedQueries
@NamedQuery
@OneToMany
@OneToOne
@OrderBy
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
@MapKey
默認情況下,JPA 持續性提供程序假設關聯實體的主鍵為 java.util.Map 類型的關聯的 Map 鍵:
如果主鍵是批注為 @Id 的非復合主鍵,則該字段或屬性的類型實例將用作 Map 鍵。
如果主鍵是批注為 @IdClass 的復合主鍵,則主鍵類的實例將用作 Map 鍵。
使用 @MapKey 批注:
● 將某個其他字段或屬性指定為 Map 鍵(如果關聯實體的主鍵不適合于應用程序)
● 指定一個嵌入的復合主鍵類(請參閱 @EmbeddedId)
● 指定的字段或屬性必須具有唯一約束(請參閱 @UniqueConstraint)。
表 1-24 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-24 @MapKey 屬性
屬性
|
必需
|
說明
|
name |

|
默認值:默認情況下,JPA 持續性提供程序將關聯實體的主鍵作為 Map 鍵,以用于映射到非復合主鍵或復合主鍵(批注為 @IdClass)的 java.util.Map 的屬性或字段。
如果要將某個其他字段或屬性用作 Map 鍵,請將 name 設置為要使用的關聯實體的 String 字段或屬性名。 |
在示例 1-52 中,Project 對作為 Map 的 Employee 實例擁有一對多關系。示例 1-52 顯示了如何使用 @MapKey 批注指定此 Map 的鍵為 Employee 字段 empPK,它是一個類型為 EmployeePK(請參閱示例 1-52)的嵌入式復合主鍵(請參閱示例 1-51)。
示例 1-50 使用 @MapKey 的 Project 實體
@Entity
public class Project {
...
@OneToMany(mappedBy="project")
@MapKey(name="empPK")
public Map<EmployeePK, Employee> getEmployees() {
...
}
...
}
示例 1-51 Employee 實體
@Entity
public class Employee {
@EmbeddedId
public EmployeePK getEmpPK() {
...
}
...
@ManyToOne
@JoinColumn(name="proj_id")
public Project getProject() {
...
}
...
}
示例 1-52 EmployeePK 復合主鍵類
@Embeddable
public class EmployeePK {
String name;
Date birthDate;
}
@MappedSuperclass
默認情況下,JPA 持續性提供程序假設實體的所有持久字段均在該實體中定義。
使用 @MappedSuperclass 批注指定一個實體類從中繼承持久字段的超類。當多個實體類共享通用的持久字段或屬性時,這將是一個方便的模式。
您可以像對實體那樣使用任何直接和關系映射批注(如 @Basic 和 @ManyToMany)對該超類的字段和屬性進行批注,但由于沒有針對該超類本身的表存在,因此這些映射只適用于它的子類。繼承的持久字段或屬性屬于子類的表。
可以在子類中使用 @AttributeOverride 或 @AssociationOverride 批注來覆蓋超類的映射配置。
該批注沒有屬性。有關更多詳細信息,請參閱 API。
示例 1-53 顯示了如何使用此批注將 Employee 指定為映射超類。示例 1-54 顯示了如何擴展實體中的此超類,以及如何在實體類中使用 @AttributeOverride 以覆蓋超類中設置的配置。
示例 1-53 @MappedSuperclass
@MappedSuperclass
public class Employee {
@Id
protected Integer empId;
@Version
protected Integer version;
@ManyToOne
@JoinColumn(name="ADDR")
protected Address address;
public Integer getEmpId() {
...
}
public void setEmpId(Integer id) {
...
}
public Address getAddress() {
...
}
public void setAddress(Address addr) {
...
}
}
示例 1-54 擴展 @MappedSuperclass
@Entity
@AttributeOverride(name="address", column=@Column(name="ADDR_ID"))
public class PartTimeEmployee extends Employee {
@Column(name="WAGE")
protected Float hourlyWage;
public PartTimeEmployee() {
...
}
public Float getHourlyWage() {
...
}
public void setHourlyWage(Float wage) {
...
}
}
@NamedNativeQueries
如果需要指定多個 @NamedNativeQuery,則必須使用一個 @NamedNativeQueries 批注指定所有命名查詢。
表 1-25 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-25 @NamedNativeQueries 屬性
屬性
|
必需
|
說明
|
value |

|
要指定兩個或更多屬性覆蓋,請將 value 設置為 NamedNativeQuery 實例數組(請參閱 @NamedNativeQuery)。 |
示例 1-55 顯示了如何使用此批注指定兩個命名原生查詢。
示例 1-55 @NamedNativeQueries
@Entity
@NamedNativeQueries({
@NamedNativeQuery(
name="findAllPartTimeEmployees",
query="SELECT * FROM EMPLOYEE WHERE PRT_TIME=1"
),
@NamedNativeQuery(
name="findAllSeasonalEmployees",
query="SELECT * FROM EMPLOYEE WHERE SEASON=1"
)
})
public class PartTimeEmployee extends Employee {
...
}
@NamedNativeQuery
在使用 JPA 持續性提供程序的應用程序中,可以使用實體管理器動態創建和執行查詢,也可以預定義查詢并在運行時按名稱執行。
使用 @NamedNativeQuery 批注創建與 @Entity 或 @MappedSuperclass 關聯的預定義查詢,這些查詢:
● 使用基礎數據庫的原生 SQL
● 經常被使用
● 比較復雜并且難于創建
● 可以在不同實體之間共享
● 返回實體、標量值或兩者的組合(另請參閱 @ColumnResult、@EntityResult、@FieldResult 和@SqlResultSetMapping)
如果有多個要定義的 @NamedNativeQuery,則必須使用 @NamedNativeQueries。
要預定義適合于任何數據庫的可移植查詢,請參閱 @NamedQuery。
表 1-26 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-26 @NamedNativeQuery 屬性
屬性
|
必需
|
說明
|
query |

|
要指定查詢,請將 query 設置為 SQL 查詢(作為 String)。
有關原生 SQL 查詢語言的詳細信息,請參閱數據庫文檔。 |
hints |

|
默認值:空 QueryHint 數組。
默認情況下,JPA 持續性提供程序假設 SQL 查詢應完全按照 query 屬性提供的方式執行。
要微調查詢的執行,可以選擇將 hints 設置為一個 QueryHint 數組(請參閱 @QueryHint)。在執行時,EntityManager 將向基礎數據庫傳遞提示。 |
name |

|
要指定查詢名稱,請將 name 設置為所需的 String 名稱。
這是您在運行時調用查詢所使用的名稱(請參閱示例 1-56)。 |
resultClass |

|
默認值:JPA 持續性提供程序假設結果類是關聯實體的 Class。
要指定結果類,請將 resultClass 設置為所需的 Class。 |
resultSetMapping |

|
默認值:JPA 持續性提供程序假設原生 SQL 查詢中的 SELECT 語句:返回一個類型的實體;包括與返回的實體的所有字段或屬性相對應的所有列;并使用與字段或屬性名稱(未使用 AS 語句)相對應的列名。
要控制 JPA 持續性提供程序如何將 JDBC 結果集映射到實體字段或屬性以及標量,請通過將 resultSetMapping 設置為所需的 @SqlResultSetMapping 的 String 名稱來指定結果集映射。 |
示例 1-56 顯示了如何使用 @NamedNativeQuery 批注定義一個使用基礎數據庫的原生 SQL 的查詢。示例 1-57 顯示了如何使用 EntityManager 獲取此查詢以及如何通過 Query 方法 getResultList 執行該查詢。
示例 1-56 使用 @NamedNativeQuery 實現一個 Oracle 層次查詢
@Entity
@NamedNativeQuery(
name="findAllEmployees",
query="SELECT * FROM EMPLOYEE"
)
public class Employee implements Serializable {
...
}
示例 1-57 執行一個命名原生查詢
Query queryEmployees = em.createNamedQuery("findAllEmployees");
Collection employees = queryEmployees.getResultList();
@NamedQueries
如果需要指定多個 @NamedQuery,則必須使用一個 @NamedQueries 批注指定所有命名查詢。
表 1-27 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-27 @NamedQueries 屬性
屬性
|
必需
|
說明
|
value |

|
要指定兩個或更多屬性覆蓋,請將 value 設置為 NamedQuery 實例數組(請參閱 @NamedQuery)。 |
示例 1-58 顯示了如何使用此批注指定兩個命名查詢。
示例 1-58 @NamedQueries
@Entity
@NamedQueries({
@NamedQuery(
name="findAllEmployeesByFirstName",
query="SELECT OBJECT(emp) FROM Employee emp WHERE emp.firstName = :firstname"
),
@NamedQuery(
name="findAllEmployeesByLasttName",
query="SELECT OBJECT(emp) FROM Employee emp WHERE emp.lasstName = :lastname"
)
})
public class PartTimeEmployee extends Employee {
...
}
@NamedQuery
在使用 JPA 持續性提供程序的應用程序中,可以使用實體管理器動態創建和執行查詢,也可以預定義查詢并在運行時按名稱執行。
使用 @NamedQuery 批注創建與 @Entity 或 @MappedSuperclass 關聯的預定義查詢,這些查詢:
● 使用 JPA 查詢語言(請參閱 JSR-000220 Enterprise JavaBeans v3.0 規范,第 4 章)進行基于任何基礎數據庫的可移植執行
● 經常被使用
● 比較復雜并且難于創建
● 可以在不同實體之間共享
● 只返回實體(從不返回標量值),并只返回一個類型的實體
如果有多個要定義的 @NamedQuery,則必須使用 @NamedQueries。
要在已知的基礎數據庫中預定義原生 SQL 查詢,請參閱 @NamedNativeQuery。使用原生 SQL 查詢,您可以返回實體(包括不同類型的實體)、標量值或同時返回兩者。
表 1-28 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-28 @NamedQuery 屬性
屬性
|
必需
|
說明
|
query |

|
要指定查詢,請將 query 設置為 JPA 查詢語言(作為 String)。
有關 JPA 查詢語言的詳細信息,請參閱 JSR-000220 Enterprise JavaBeans v.3.0 規范的第 4 章。 |
hints |

|
默認值:空 QueryHint 數組。
默認情況下,JPA 持續性提供程序假設 SQL 查詢應完全按照 query 屬性提供的方式執行,而不管基礎數據庫如何。
如果您知道基礎數據庫在運行時的狀態,則要微調查詢的執行,可以選擇將 hints 設置為 QueryHint 數組(請參閱 @QueryHint)。在執行時,EntityManager 將向基礎數據庫傳遞提示。 |
name |

|
要指定查詢名稱,請將 name 設置為查詢名稱(作為 String)。
這是您在運行時調用查詢所使用的名稱(請參閱示例 1-59)。 |
示例 1-59 顯示了如何使用 @NamedQuery 批注定義一個JPA 查詢語言查詢,該查詢使用名為 firstname 的參數。示例 1-60 顯示了如何使用 EntityManager 獲取此查詢并使用 Query 方法 setParameter 設置 firstname 參數。
示例 1-59 使用 @NamedQuery 實現一個帶參數的查詢
@Entity
@NamedQuery(
name="findAllEmployeesByFirstName",
query="SELECT OBJECT(emp) FROM Employee emp WHERE emp.firstName = :firstname"
)
public class Employee implements Serializable {
...
}
示例 1-60 執行命名查詢
Query queryEmployeesByFirstName = em.createNamedQuery("findAllEmployeesByFirstName");
queryEmployeeByFirstName.setParameter("firstName", "John");
Collection employees = queryEmployessByFirstName.getResultList();
@OneToMany
默認情況下,JPA 為具有一對多多重性的多值關聯定義一個 OneToMany 映射。
使用 @OneToMany 批注:
● 將獲取類型配置為 LAZY
● 由于所使用的 Collection 不是使用一般參數定義的,因此配置關聯的目標實體
● 配置必須層疊到關聯目標的操作:例如,如果刪除了擁有實體,則確保還刪除關聯的目標
● 配置持續性提供程序對單向一對多關系使用的連接表(請參閱 @JoinTable)的詳細信息
表 1-29 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-29 @OneToMany 屬性
屬性
|
必需
|
說明
|
cascade
|

|
默認值:CascadeType 的空數組。
默認情況下,JPA 不會將任何持續性操作層疊到關聯的目標。
如果希望某些或所有持續性操作層疊到關聯的目標,請將 cascade 設置為一個或多個 CascadeType 實例,其中包括:
● ALL - 針對擁有實體執行的任何持續性操作均層疊到關聯的目標。
● MERGE - 如果合并了擁有實體,則將 merge 層疊到關聯的目標。
● PERSIST - 如果持久保存擁有實體,則將 persist 層疊到關聯的目標。
● REFRESH - 如果刷新了擁有實體,則 refresh 為關聯的層疊目標。
● REMOVE - 如果刪除了擁有實體,則還刪除關聯的目標。 |
fetch |

|
默認值:FetchType.EAGER。
默認情況下,JPA 持續性提供程序使用獲取類型 EAGER:它要求持續性提供程序運行時必須急性獲取數據。
如果這不適合于應用程序或特定的持久字段,請將 fetch 設置為 FetchType.LAZY:它提示持續性提供程序在首次訪問數據(如果可以)時應惰性獲取數據。 |
mappedBy |

|
默認值:如果關系是單向的,則該持續性提供程序確定擁有該關系的字段。
如果關系是雙向的,則將關聯相反(非擁有)方上的 mappedBy 元素設置為擁有此關系的字段或屬性的名稱(如示例 1-61 所示)。 |
targetEntity |

|
默認值:使用一般參數定義的 Collection 的參數化類型。
默認情況下,如果使用通過一般參數定義的 Collection,則持續性提供程序將從被引用的對象類型推斷出關聯的目標實體。
如果 Collection 不使用一般參數,則必須指定作為關聯目標的實體類:將關聯擁有方上的 targetEntity 元素設置為作為關系目標的實體的 Class。 |
示例 1-61 和示例 1-62 顯示了如何使用此批注在使用一般參數的 Customer(被擁有方)和 Order(擁有方)之間配置一個一對多映射。
示例 1-61 @OneToMany - 使用一般參數的 Customer 類
@Entity
public class Customer implements Serializable {
...
@OneToMany(cascade=ALL, mappedBy="customer")
public Set<Order> getOrders() {
return orders;
}
...
}
示例 1-62 @ManyToOne - 使用一般參數的 Order 類
@Entity
public class Customer implements Serializable {
...
@ManyToOne
@JoinColumn(name="CUST_ID", nullable=false)
public Customer getCustomer() {
return customer;
}
...
}
@OneToOne
默認情況下,JPA 為指向另一個具有一對一多重性的實體的單值關聯定義一個 OneToOne 映射,并從被引用的對象類型推斷出關聯的目標實體。
使用 @OneToOne 批注:
● 將獲取類型配置為 LAZY
● 如果空值不適合于應用程序,則將映射配置為禁止空值(針對非基元類型)
● 配置關聯的目標實體(如果無法從被引用的對象類型推斷出它)
● 配置必須層疊到關聯目標的操作:例如,如果刪除了擁有實體,則確保還刪除關聯的目標
表 1-30 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-30 @OneToOne 屬性
屬性
|
必需
|
說明
|
cascade
|

|
默認值:CascadeType 的空數組。
默認情況下,JPA 不會將任何持續性操作層疊到關聯的目標。
如果希望某些或所有持續性操作層疊到關聯的目標,請將 cascade 設置為一個或多個 CascadeType 實例,其中包括:
● ALL - 針對擁有實體執行的任何持續性操作均層疊到關聯的目標。
● MERGE - 如果合并了擁有實體,則將 merge 層疊到關聯的目標。
● PERSIST - 如果持久保存擁有實體,則將 persist 層疊到關聯的目標。
● REFRESH - 如果刷新了擁有實體,則 refresh 為關聯的層疊目標。
● REMOVE - 如果刪除了擁有實體,則還刪除關聯的目標。 |
fetch |

|
默認值:FetchType.EAGER。
默認情況下,JPA 持續性提供程序使用獲取類型 EAGER:它要求持續性提供程序運行時必須急性獲取數據。
如果這不適合于應用程序或特定的持久字段,請將 fetch 設置為 FetchType.LAZY:它提示持續性提供程序在首次訪問數據(如果可以)時應惰性獲取數據。 |
mappedBy |

|
默認值:如果關系是單向的,則該持續性提供程序確定擁有該關系的字段。
如果關系是雙向的,則將關聯相反(非擁有)方上的 mappedBy 元素設置為擁有此關系的字段或屬性的名稱(如示例 1-64 所示)。 |
optional
|

|
默認值:true。
默認情況下,JPA 持續性提供程序假設所有(非基元)字段和屬性的值可以為空。
如果這并不適合于您的應用程序,請將 optional 設置為 false。 |
targetEntity |

|
默認值:JPA 持續性提供程序從被引用的對象類型推斷出關聯的目標實體。
如果持續性提供程序無法推斷出目標實體的類型,則將關聯的擁有方上的 targetEntity 元素設置為作為關系目標的實體的 Class。 |
示例 1-63 和示例 1-64 顯示了如何使用此批注在 Customer(擁有方)和 CustomerRecord(被擁有方)之間配置一個一對一映射。
示例 1-63 @OneToOne - Customer 類
@Entity
public class Customer implements Serializable {
...
@OneToOne(optional=false)
@JoinColumn(name="CUSTREC_ID", unique=true, nullable=false, updatable=false)
public CustomerRecord getCustomerRecord() {
return customerRecord;
}
...
}
示例 1-64 @OneToOne - CustomerRecord 類
@Entity
public class CustomerRecord implements Serializable {
...
@OneToOne(optional=false, mappedBy="customerRecord")
public Customer getCustomer() {
return customer;
}
...
}
@OrderBy
默認情況下,JPA 持續性提供程序按關聯實體的主鍵以升序順序檢索 Collection 關聯的成員。
將 @OrderBy 批注與 @OneToMany 和 @ManyToMany 一起使用以便:
● 指定一個或多個作為排序依據的其他字段或屬性
● 為每個這樣的字段或屬性名指定不同的排序(升序或降序)
表 1-31 列出了此批注的屬性。有關更多詳細信息,請參閱 API。
表 1-31 @OrderBy 屬性
屬性
|
必需
|
說明
|
value |

|
默認值:JPA 持續性提供程序按關聯實體的主鍵以升序順序檢索 Collection 關聯的成員。
如果要按某些其他字段或屬性排序并指定了不同的排序,則將 value 設置為以下元素的逗號分隔列表:"property-or-field-name ASC|DESC”(請參閱示例 1-65)。 |
示例 1-65 顯示了如何使用 @OrderBy 批注指定 Project 方法 getEmployees 應按 Employee 字段 lastname 以升序順序并按 Employee 字段 seniority 以降序順序返回 Employee 的 List。示例 1-66 顯示了默認情況下,Employee 方法 getProjects 按 Employee 主鍵 empId 以升序順序返回 List。
示例 1-65 Project 實體
@Entity public class Project {
...
@ManyToMany
@OrderBy("lastname ASC", "seniority DESC")
public List<Employee> getEmployees() {
...
};
...
}
示例 1-66 Employee 實體
@Entity public class Employee {
@Id
private int empId;
...
private String lastname;
...
private int seniority;
...
@ManyToMany(mappedBy="employees")
// By default, returns a List in ascending order by empId
public List<Project> getProjects() {
...
};
...
}