@JoinColumn
默认情况下,在实体关联中,JPA 持续性提供程序使用一个基于现有名称(如字段或属性名称)的数据库模式,以便它可以自动确定要使用的单个连接列(包含外键的列)。
在以下条件下使用 @JoinColumn 批注:
-
默认连接列名称难于处理、是一个保留字、与预先存在的数据模型不兼容或作为数据库中的列名无效
-
您需要使用外部表中的列(非主键列)进行连接
-
您想要使用两个或更多连接列(请参阅 @JoinColumns)
-
您想要使用一个连接表(请参阅 @JoinTable)
表 1-19 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-43 显示了如何使用此批注使 JPA 将数据库表 Employee 列 ADDR_ID 用作连接列。
示例 1-43 @JoinColumn
@Entity
public class Employee implements Serializable {
...
@ManyToOne
@JoinColumn(name="ADDR_ID")
public Address getAddress() {
return address;
}
}
@JoinColumns
默认情况下,在实体关联中,JPA 持续性提供程序假设使用一个连接列。
如果要指定两个或更多连接列(即复合主键),请使用 @JoinColumns 批注。
表 1-20 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-44 显示了如何使用此批注指定两个连接列的名称:Employee 表中的 ADDR_ID(其中包含 Address 表列 ID 中的外键值)以及 Employee 表中的 ADDR_ZIP(其中包含 Address 表列 ZIP 中的外键值)。
示例 1-44 @JoinColumns
@Entity
public class Employee implements Serializable {
...
@ManyToOne
@JoinColumns({
@JoinColumn(name="ADDR_ID", referencedColumnName="ID"),
@JoinColumn(name="ADDR_ZIP", referencedColumnName="ZIP")
})
public Address getAddress() {
return address;
}
...
}
@JoinTable
默认情况下,JPA 持续性提供程序在映射多对多关联(或在单向的一对多关联中)的拥有方上的实体关联时使用一个连接表。连接表名称及其列名均在默认情况下指定,且 JPA 持续性提供程序假设:在关系的拥有方上的实体主表中,每个主键列有一个连接列。
如果您需要执行以下操作,请使用 @JoinTable 批注:
表 1-21 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-45 显示了如何使用此批注为 Employee 与 Project 之间实体的多对多关系指定一个名为 EMP_PROJ_EMP 的连接表。连接表中有两列:EMP_ID 和 PROJ_ID。EMP_ID 列包含其主键列(被引用列)名为 ID 的 Employee 表中的主键值。PROJ_ID 列包含其主键列(被引用列)也名为 ID 的 Project 表中的主键值。
示例 1-45 @JoinTable
@Entity
public class Employee implements Serializable {
...
@ManyToMany
@JoinTable(
name="EJB_PROJ_EMP",
joinColumns=@JoinColumn(name="EMP_ID", referencedColumnName="ID"),
inverseJoinColumns=@JoinColumn(name="PROJ_ID", referencedColumnName="ID")
)
public Collection getProjects() {
return projects;
}
...
}
@Lob
默认情况下,JPA 持续性提供程序假设所有持久数据均可以表示为典型的数据库数据类型。
结合使用 @Lob 批注与 @Basic 映射,以指定持久属性或字段应作为大型对象持久保存到数据库支持的大型对象类型。
Lob 可以是二进制类型或字符类型。持续性提供程序从持久字段或属性的类型推断出 Lob 类型。
对于基于字符串和字符的类型,默认值为 Clob。在所有其他情况下,默认值为 Blob。
还可以使用 @Column 属性 columnDefinition 进一步改进 Lob 类型。
此批注没有属性。有关更多详细信息,请参阅 API。
示例 1-46 显示了如何使用此批注指定持久字段 pic 应作为 Blob 进行持久保存。
示例 1-46 @Lob
@Entity
public class Employee implements Serializable {
...
@Lob
@Basic(fetch=LAZY)
@Column(name="EMP_PIC", columnDefinition="BLOB NOT NULL")
protected byte[] pic;
...
}
@ManyToMany
默认情况下,JPA 为具有多对多多重性的为多值关联自动定义一个 @ManyToMany 映射。
使用 @ManyToMany 批注:
-
将获取类型配置为 LAZY
-
如果空值不适合于应用程序,则将映射配置为禁止空值(针对非基元类型)
-
由于所使用的 Collection 不是使用一般参数定义的,因此配置关联的目标实体
-
配置必须层叠到关联目标的操作:例如,如果删除了拥有实体,则确保还删除关联的目标
-
配置由持续性提供程序使用的连接表的详细信息(请参阅 @JoinTable)
表 1-22 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-47 和示例 1-48 显示了如何使用此批注在使用一般参数的 Customer 和 PhoneNumber 之间配置一个多对多映射。
示例 1-47 @ManyToMany — 使用一般参数的 Customer 类
@Entity
public class Customer implements Serializable {
...
@ManyToMany
@JoinTable(
name="CUST_PHONE",
joinColumns=
@JoinColumn(name="CUST_ID", referencedColumnName="ID"),
inverseJoinColumns=
@JoinColumn(name="PHONE_ID", referencedColumnName="ID")
)
public Set<PhoneNumber> getPhones() {
return phones;
}
...
}
示例 1-48 @ManyToMany — 使用一般参数的 PhoneNumber 类
@Entity
public class PhoneNumber implements Serializable {
...
@ManyToMany(mappedBy="phones")
public Set<Customer> getCustomers() {
return customers;
}
...
}
@ManyToOne
默认情况下,JPA 为指向具有多对一多重性的其他实体类的单值关联自动定义一个 ManyToOne 映射。
使用 @ManyToOne 批注:
-
将获取类型配置为 LAZY
-
如果空值不适合于应用程序,则将映射配置为禁止空值(针对非基元类型)
-
配置关联的目标实体(如果无法从被引用的对象类型推断出它)
-
配置必须层叠到关联目标的操作:例如,如果删除了拥有实体,则确保还删除关联的目标
表 1-23 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-49 显示了如何使用此批注在使用一般参数的 Customer(被拥有方)和 Order(拥有方)之间配置一个多对一映射。
示例 1-49 @ManyToOne
@Entity
public class Order implements Serializable {
...
@ManyToOne(optional=false)
@JoinColumn(name="CUST_ID", nullable=false, updatable=false)
public Customer getCustomer() {
return customer;
}
...
}
@MapKey
默认情况下,JPA 持续性提供程序假设关联实体的主键为 java.util.Map 类型的关联的 Map 键:
使用 @MapKey 批注:
指定的字段或属性必须具有唯一约束(请参阅 @UniqueConstraint)。
表 1-24 列出了此批注的属性。有关更多详细信息,请参阅 API。
在示例 1-52 中,Project 对作为 Map 的 Employee 实例拥有一对多关系。示例 1-52 显示了如何使用 @MapKey 批注指定此 Map 的键为 Employee 字段 empPK,它是一个类型为 EmployeePK(请参阅示例 1-52)的嵌入式复合主键(请参阅示例 1-51)。
示例 1-50 使用 @MapKey 的 Project 实体
@Entitypublic class Project { ...@OneToMany(mappedBy="project") @MapKey(name="empPK") public Map<EmployeePK, Employee> getEmployees() { ...
} ...}
示例 1-51 Employee 实体
@Entitypublic class Employee { @EmbeddedId public EmployeePK getEmpPK() { ...
} ... @ManyToOne @JoinColumn(name="proj_id") public Project getProject() {
...
}...}
示例 1-52 EmployeePK 复合主键类
@Embeddablepublic 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-5 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-6 显示了如何使用此批注指定两个命名原生查询。
示例 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 关联的预定义查询,这些查询:
如果有多个要定义的 @NamedNativeQuery,则必须使用 @NamedNativeQueries。
要预定义适合于任何数据库的可移植查询,请参阅 @NamedQuery。
表 1-6 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-59 显示了如何使用 @NamedNativeQuery 批注定义一个使用基础数据库的原生 SQL 的查询。示例 1-60 显示了如何使用 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-5 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 1-6 显示了如何使用此批注指定两个命名查询。
示例 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 关联的预定义查询,这些查询:
如果有多个要定义的 @NamedQuery,则必须使用 @NamedQueries。
要在已知的基础数据库中预定义原生 SQL 查询,请参阅 @NamedNativeQuery。使用原生 SQL 查询,您可以返回实体(包括不同类型的实体)、标量值或同时返回两者。
表 1-6 列出了此批注的属性。有关更多详细信息,请参阅 API。
示例 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-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-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;
}
...
}