来源:www.oracle.com
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
本文的主要内容如下:
详细解释了下面8个批注的含义及其批注所包含的属性:
@Basic
@Column
@ColumnResult
@DiscriminatorColumn
@DiscriminatorValue
@Embeddable
@Embedded
@EmbeddedId
■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
@Basic
默认情况下,JPA 持续性提供程序为大多数 Java 基元类型、基元类型的包装程序以及枚举自动配置一个 @Basic
映射。
使用 @Basic
批注:
-
将获取类型配置为
LAZY
-
如果空值不适合于应用程序,则将映射配置为禁止空值(针对非基元类型)
表 1-6 列出了此批注的属性。有关更多详细信息,请参阅 API。
表 1-6 @Basic 属性
属性 | 必需 | 说明 |
---|---|---|
fetch |
![]() | 默认值:FetchType.EAGER。 默认情况下,JPA 持续性提供程序使用获取类型 EAGER:这将要求持续性提供程序运行时必须迫切获取数据。 如果这不适合于应用程序或特定的持久字段,请将 fetch 设置为 FetchType.LAZY:这将提示持续性提供程序在首次访问数据(如果可以)时应不急于获取数据。 |
optional |
![]() | 默认值:true。 默认情况下,JPA 持续性提供程序假设所有(非基元)字段和属性的值可以为空。 如果这并不适合于您的应用程序,请将 optional 设置为 false。 |
示例 1-7 显示了如何使用此批注为基本映射指定获取类型 LAZY
。
示例 1-7 @Basic
@Entity public class Employee implements Serializable { ... @Basic(fetch=LAZY) protected String getName() { return name; } ... }
@Column
默认情况下,JPA 持续性提供程序假设每个实体的持久字段存储在其名称与持久字段的名称相匹配的数据库表列中。
使用 @Column
批注:
-
将持久字段与其他名称关联(如果默认列名难于处理、与事先存在的数据模型不兼容或作为数据库中的列名无效)
-
将持久字段与辅助表中的列关联(请参阅 @SecondaryTable)
-
微调数据库中列的特征
表 1-7 列出了此批注的属性。有关更多详细信息,请参阅 API。
表 1-7 @Column 属性
属性 | 必需 | 说明 |
---|---|---|
|
![]() | 默认值:空 String。 |
|
![]() | 默认值:true。 |
length |
![]() | 默认值: 255 默认情况下,JPA 持续性提供程序假设所有列在用于保存 String 值时的最大长度为 255 个字符。 如果该列不适合于您的应用程序或数据库,请将 length 设置为适合于您的数据库列的 int 值。 |
name |
![]() | 默认值:JPA 持续性提供程序假设实体的每个持久字段都存储在其名称与持久字段或属性的名称相匹配的数据库表列中。 要指定其他列名,请将 name 设置为所需的 String 列名 |
nullable |
![]() | 默认值:true。 默认情况下,JPA 持续性提供程序假设允许所有列包含空值。 如果不允许该列包含空值,请将 nullable 设置为 false。 |
precision |
![]() | 默认值: 0。 默认情况下,JPA 持续性提供程序假设所有列在用于保存十进制(精确数字)值时的精度为 0。 如果该精度不适合于您的应用程序或数据库,请将 precision 设置为相应的 int 精度。 |
scale |
![]() | 默认值: 0。 默认情况下,JPA 持续性提供程序假设所有列在用于保存十进制(精确数字)值时的伸缩度为 0。 如果该伸缩度不适合于您的应用程序或数据库,请将 scale 设置为相应的 int 精度。 |
table |
![]() | 默认值:JPA 持续性提供程序假设实体的所有持久字段都存储到一个其名称为实体名称的数据库表中(请参阅 @Table)。 如果该列与辅助表关联(请参阅 @SecondaryTable),请将 name 设置为相应辅助表名称的 String 名称,如示例 1-8 所示。 |
unique |
![]() | 默认值:false。 默认情况下,JPA 持续性提供程序假设允许所有列包含重复值。 如果不允许该列包含重复值,请将 unique 设置为 true。设置为 true 时,这相当于在表级别使用 @UniqueConstraint。 |
updatable |
![]() | 默认值:true。 默认情况下,JPA 持续性提供程序假设列始终包含在 SQL UPDATE 语句中。 如果该列不应包含在这些语句中,请将 updatable 设置为 false。 |
示例 1-8 显示了如何使用此批注使 JPA 将 empId
持久保存到辅助表 EMP_HR
中的列 EMP_NUM
。默认情况下,JPA 将 empName
持久保存到主表 Employee
中的列 empName
。
示例 1-8 @Column
@Entity @SecondaryTable(name="EMP_HR") public class Employee implements Serializable { ... @Column(name="EMP_NUM", table="EMP_HR") private Long empId; private String empName; ... }
@ColumnResult
执行 @NamedNativeQuery 时,它可以返回实体(包括不同类型的实体)、标量值或实体和标量值的组合。
使用 @ColumnResult
批注返回标量值。标量类型由您在 @ColumnResult
中标识的列类型确定。
有关详细信息,另请参阅 @EntityResult、@FieldResult 和 @SqlResultSetMapping。
表 1-8 列出了此批注的属性。有关更多详细信息,请参阅 API。
表 1-8 @ColumnResult 属性
属性 | 必需 | 说明 |
---|---|---|
name | | 在原生 SQL 查询的 SELECT 语句中将 name 设置为列名的 String 等效形式。如果在 SELECT 中使用列别名(AS 语句),则将 name 设置为列别名。 |
示例 1-9 显示了如何使用此批注将 Item
(请参阅示例 1-10)标量 name
包含在结果列表(请参阅示例 1-11)中。在该示例中,结果列表将为 Object
数组的 List
,如:{[Order, "Shoes"], [Order, "Socks"], ...}
。
示例 1-9 使用 @ColumnResult 的 Order 实体
@SqlResultSetMapping( name="OrderResults", entities={ @EntityResult( entityClass=Order.class, fields={ @FieldResult(name="id", column="order_id"), @FieldResult(name="quantity", column="order_quantity"), @FieldResult(name="item", column="order_item") } ) }, columns={ @ColumnResult( name="item_name" ) } ) @Entity public class Order { @Id protected int id; protected long quantity; protected Item item; ... }
示例 1-11 结合使用 @SqlResultSetMapping 与 @ColumnResult 的原生查询
Query q = entityManager.createNativeQuery( "SELECT o.id AS order_id, " + "o.quantity AS order_quantity, " + "o.item AS order_item, " + "i.name AS item_name, " + "FROM Order o, Item i " + "WHERE (order_quantity > 25) AND (order_item = i.id)", "OrderResults" ); List resultList = q.getResultList(); // List of Object arrays:{[Order, "Shoes"], [Order, "Socks"], ...}
@DiscriminatorColumn
默认情况下,当 @Inheritance 属性策略为 InheritanceType.SINGLE_TABLE
或 JOINED
时,JPA 持续性提供程序将创建一个名为 DTYPE
的标识符列以区分继承层次中的类。
使用 @DiscriminatorColumn
批注:
-
指定一个标识符列名(如果数据模型中的列名不是默认列名
DTYPE
)。 -
指定一个适用于应用程序或事先存在的数据模型的标识符列长度
-
微调数据库中的标识符列的特征
表 1-9 列出了此批注的属性。有关更多详细信息,请参阅 API。
表 1-9 @DiscriminatorColumn 属性
属性 | 必需 | 说明 |
---|---|---|
|
![]() | 默认值:空 String。 |
|
![]() | 默认值:DiscriminatorType.STRING。 默认情况下,JPA 持续性提供程序假设标识符类型为 String。 如果要使用其他类型,请将 discriminatorType 设置为 DiscriminatorType.CHAR 或 DiscriminatorType.INTEGER。 您的 @DiscriminatorValue 必须符合此类型。 |
length |
![]() | 默认值: 31。 默认情况下,JPA 持续性提供程序假设标识符列在用于保存 String 值时的最大长度为 255 个字符。 如果该列不适合于您的应用程序或数据库,请将 length 设置为适合于您的数据库列的 int 值。 您的 @DiscriminatorValue 必须符合此长度。 |
name |
![]() | 默认值:JPA 持续性提供程序假设标识符列名为“DTYPE”。 |
示例 1-12 显示了如何使用此批注指定一个名为 DISC
、类型为 STRING
、长度为 20 的标识符列。在本示例中,该类的 @DiscriminatorValue 指定为 CUST
。示例 1-13 中的子类将它自己的 @DiscriminatorValue 指定为 VIP
。在 Customer
和 ValuedCustomer
中,@DiscriminatorValue 的值必须可以转换为由 @DiscriminatorColumn 属性 discriminatorType
指定的类型,并且必须符合 @DiscriminatorColumn 属性 length
。
示例 1-12 @DiscriminatorColumn 和 @DiscriminatorValue — 根类
@Entity @Table(name="CUST") @Inheritance(strategy=SINGLE_TABLE) @DiscriminatorColumn(name="DISC", discriminatorType=STRING, length=20) @DiscriminatorValue(value-"CUST") public class Customer { ... }
示例 1-13 @DiscriminatorValue — 子类
@Entity @DiscriminatorValue(value="VIP") public class ValuedCustomer extends Customer { ... }
@DiscriminatorValue
默认情况下,当 @Inheritance 属性策略为 InheritanceType.SINGLE_TABLE
或 JOINED
时,JPA 持续性提供程序使用 @DiscriminatorColumn 按实体名称区分继承层次中的类(请参阅 @Entity)。
使用 @DiscriminatorValue
批注指定用于区分此继承层次中的实体的标识符值:
-
如果实体名称不适合于此应用程序
-
匹配现有的数据库模式
表 1-10 列出了此批注的属性。有关更多详细信息,请参阅 API。
表 1-10 @DiscriminatorValue 属性
属性 | 必需 | 说明 |
---|---|---|
value | | 将 value 设置为符合 @DiscriminatorColumn 属性 discriminatorType 和 length 的标识符值的 String 等效形式。 |
示例 1-14 显示了如何使用此批注指定一个名为 DISC
、类型为 STRING
、长度为 20 的标识符列。在本示例中,该类的 @DiscriminatorValue 指定为 CUST
。示例 1-15 中的子类将它自己的 @DiscriminatorValue 指定为 VIP
。在 Customer
和 ValuedCustomer
中,@DiscriminatorValue 的值必须可以转换为由 @DiscriminatorColumn 属性 discriminatorType
指定的类型,并且必须符合 @DiscriminatorColumn 属性 length
。
示例 1-14 @DiscriminatorColumn 和 @DiscriminatorValue — 根类
@Entity @Table(name="CUST") @Inheritance(strategy=SINGLE_TABLE) @DiscriminatorColumn(name="DISC", discriminatorType=STRING, length=20) @DiscriminatorValue(value-"CUST") public class Customer { ... }
示例 1-15 @DiscriminatorValue — 子类
@Entity @DiscriminatorValue(value="VIP") public class ValuedCustomer extends Customer { ... }
@Embeddable
默认情况下,JPA 持续性提供程序假设每个实体均持久保存到它自己的数据库表。
使用 @Embeddable
批注指定一个类,该类的实例存储为拥有实体的固有部分并共享该实体的身份。嵌入对象的每个持久属性或字段都将映射到实体的数据库表。
此批注没有属性。有关更多详细信息,请参阅 API。
示例 1-16 显示了如何使用此批注指定:类 EmploymentPeriod
在用作批注为 @Embedded 的持久字段的类型时可以嵌套到实体中(请参阅示例 1-17)
@Embedded
默认情况下,JPA 持续性提供程序假设每个实体均持久保存到它自己的数据库表。
使用 @Embedded
批注指定一个持久字段,该字段的 @Embeddable 类型可以存储为拥有实体的固有部分,并共享该实体的身份。嵌入对象的每个持久属性或字段均映射到拥有实体的数据库表。
可以结合使用 @Embedded
和 @Embeddable 以建立严格所有权关系的模型,以便在删除了拥有对象的情况下还将删除被拥有的对象。
嵌入的对象不应映射到多个表。
默认情况下,@Embeddable 类中指定的列定义(请参阅 @Column)适用于 @Embedded
类。如果要覆盖这些列定义,请使用 @AttributeOverride。
此批注没有属性。有关更多详细信息,请参阅 API。
示例 1-17 显示了如何使用该批注指定:@Embeddable 类 EmploymentPeriod
(请参阅示例 1-16)可以使用指定的属性覆盖(请参阅 @AttributeOverride)嵌入到实体类中。如果不需要属性覆盖,则可以完全忽略 @Embedded
批注:JPA 持续性提供程序将推断出 EmploymentPeriod
是从它的 @Embeddable 批注进行嵌套。
示例 1-17 @Embedded
@Entity public class Employee implements Serializable { ... @Embedded @AttributeOverrides({ @AttributeOverride(name="startDate", column=@Column("EMP_START")), @AttributeOverride(name="endDate", column=@Column("EMP_END")) ) public EmploymentPeriod getEmploymentPeriod() { ... } ... }
@EmbeddedId
使用 @EmbeddedId
批注指定一个由实体拥有的可嵌入复合主键类(通常由两个或更多基元类型或 JDK 对象类型组成)。从原有数据库映射时(此时数据库键由多列组成),通常将出现复合主键。
复合主键类具有下列特征:
-
它是一个普通的旧式 Java 对象 (POJO) 类。
-
它必须为 public,并且必须有一个 public 无参数构造函数。
-
如果使用基于属性的访问,则主键类的属性必须为 public 或 protected。
-
它必须是可序列化的。
-
它必须定义
equals
和hashCode
方法。这些方法的值相等性的语义必须与键映射到的数据库类型的数据库相等性一致。
或者,您可以使复合主键类成为非嵌入类(请参阅 @IdClass)。
此批注没有属性。有关更多详细信息,请参阅 API。
示例 1-18 显示了一个批注为 @Embeddable 的典型复合主键类。示例1-19 显示了如何使用可嵌入的复合主键类(使用 @EmbeddedId
批注)配置一个实体。
示例 1-18 可嵌入复合主键类
@Embeddable public class EmployeePK implements Serializable { private String name; private long id; public EmployeePK() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public int hashCode() { return (int) name.hashCode() + id; } public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof EmployeePK)) return false; if (obj == null) return false; EmployeePK pk = (EmployeePK) obj; return pk.id == id && pk.name.equals(name); } }