技术开发 频道

Java EE 6引入的JPA 2.0四大新特性详解

  标准的API

  JPA 2.0中引入的另一个重要特性是标准的API,利用这个API可以动态地构建基于对象的查询,本质上,这个标准API等价于面向对象的JPQL,使用它,你可以使用基于对象的方法创建查询,不再需要JPQL使用的字符串操作。

  标准API是基于元模型的,元模型是一个提供了架构级关于持久化单元托管类的元数据的抽象模型, 元模型让你构建强类型的查询,它也允许你浏览持久化单元的逻辑结构。

  通常,一个注解处理器使用元模型生成静态元模型类,这些类提供持久化状态和持久化单元托管类的关系,但你可以对静态元模型类编码。下面是一个实体实例:

@Entity public class Employee {
      
@Id Long Id;
       String firstName;
       String lastName;
       Department dept;     }  

   下面是对应的静态元模型类:

import javax.persistence.meta,model.SingularAttribute; 
import javax.persistence.meta,model.StaticMetamodel;  
    @Generated(
"EclipseLink JPA 2.0 Canonical Model Generation"
    @StaticMetamodel(Employee.
class
    public class Employee_ {
      
public static volatile SingularAttribute<Employee, Long> id; 
      public static volatileSingularAttribute<Employee, String> firstName;
      
public static volatile SingularAttribute<Employee, String> lastName;
      
public static volatile SingularAttribute<Employee, Department> dept;
      }  

   此外,JPA 2.0元模型API允许你动态访问元模型,因此当你使用标准API时,既可以静态访问元模型类,也可以动态访问元模型类。标准API提供了更好的灵活性,既可以使用基于对象的方法,又可以使用基于字符串的方法导航元模型,这意味着你有四种使用标准API的方法:

  1、静态使用元模型类

  2、静态使用字符串

  3、动态使用元模型

  4、动态使用字符串

  无论你使用哪种方法,通过构造一个CriteriaQuery对象定义一个基于标准API的查询时,使用一个工厂对象CriteriaBuilder构造CriteriaQuery,可以从EntityManager 或 EntityManagerFactory类中获得CriteriaBuilder。下面的代码构造一个CriteriaQuery对象:

EntityManager em = ... ;
     CriteriaBuilder cb
= em.getCriteriaBuilder();
     CriteriaQuery
<Customer> cq = cb.createQuery(Customer.class);  

   注意CriteriaQuery对象是泛型类型,使用CriteriaBuilder 的createQuery方法创建一个CriteriaQuery,并为查询结果指定类型。在这个例子中,createQuery 方法的Employee.class参数指定查询结果类型是Employee。CriteriaQuery对象和创建它们的方法是强类型的。

  接下来,为CriteriaQuery对象指定一个或多个查询源,查询源表示查询基于的实体。你创建一个查询源,然后使用AbstractQuery接口的from()方法将其添加到查询。AbstractQuery接口是众多接口中的一员,如CriteriaQuery,From和root,它们都定义在标准API中。CriteriaQuery接口继承AbstractQuery接口的属性。

  from()方法的参数是实体类或EntityType实体的实例,from()方法的结果是一个Root对象,Root接口扩展From接口,它表示某个查询的from子句中可能出现的对象。

  下面的代码增加一个查询源到CriteriaQuery对象:

CriteriaBuilder cb = em.getCriteriaBuilder();
     CriteriaQuery
<Employee> cq = cb.createQuery(Employee.class);
     Root
<Employee> emp = cq.from(Employee.class);  

   当你向CriteriaQuery对象添加一个或多个查询源后,你访问元模型,然后构造一个查询表达式,你如何做取决于你是以静态方式提交查询还是以动态方式提交查询,以及是使用元模型还是字符串导航元模型。下面是一个使用元模型类静态查询的例子:

cq.select(emp);
     cq.where(cb.equal(emp.get(Employee_.lastName),
"Smith"));
     TypedQuery
<Employee> query = em.createQuery(cq);
     List
<Employee> rows = query.getResultList();  

   CriteriaQuery接口的select() 和 where()方法指定查询结果返回的选择项目。

  注意,你使用EntityManager创建查询时,可以在输入中指定一个CriteriaQuery对象,它返回一个TypedQuery,它是JPA 2.0引入javax.persistence.Query接口的一个扩展,TypedQuery接口知道它返回的类型。

  在元模型术语中,Employee_是对应于Employee实体类的规范化元模型类,一个规范化元模型类遵循JPA 2.0规范中描述的某些规则。例如,元模型类的名字来源于托管类,一般都是在托管类名字后面追加一个下划线“_”。一个规范化元模型是一个包含静态元模型类的元模型,这个静态元模型对应于实体,映射的超类,以及持久化单元中的嵌入式类。实际上,这个查询使用了规范化元模型。下面是一个完整的查询:

EntityManager em = ... ;
     CriteriaBuilder cb
= em.getCriteriaBuilder();
     CriteriaQuery
<Employee> cq = cb.createQuery(Employee.class);
     Root<Employee> emp = cq.from(Employee.class);
     cq.select(emp);
     cq.where(cb.equal(emp.get(Employee_.lastName),
"Smith"));
     TypedQuery
<Employee> query = em.createQuery(cq);
     List
<Employee> rows = query.getResultList();  

   下面是使用元模型API查询的动态版本:

EntityManager em = ... ;
     CriteriaBuilder cb
= em.getCriteriaBuilder();
     CriteriaQuery
<Employee> cq = cb.createQuery(Employee.class);
     Root
<Employee> emp = cq.from(Employee.class);
     EntityType
<Employee> emp_ = emp.getModel();
     cq.select(emp);
     cq.where(cb.equal(emp.get(emp_.getSingularAttribute(
"lastName", String.class)),"Smith"));
     TypedQuery
<Employee> query=em.createQuery(cq);
     List
<Employee> rows=query.getResultList();  

   使用元模型API的标准查询提供了与使用规范化元模型相同的类型,但它比基于规范化元模型的查询更冗长。

  Root的getModel()方法返回根对应的元模型实体,它也允许运行时访问在Employee实体中声明的持久化属性。

  getSingularAttribute()方法是一个元模型API方法,它返回一个持久化的单值属性或字段,在这个例子中,它返回值为Smith 的lastName属性。下面是使用字符串的元数据导航查询的静态版本:

EntityManager em = ... ;
     CriteriaBuilder cb
= em.getCriteriaBuilder();
     CriteriaQuery
<Employee> cq = cb.createQuery(Employee.class);
     Root
<Employee> emp = cq.from(Employee.class);
     cq.select(emp);
     cq.where(cb.equal(emp.get(
"lastName"), "Smith"));
     TypedQuery query
= em.createQuery(cq);
     List
<Employee>rows = query.getResultList();  

   这个基于字符串的方法要相对容易使用些,但却失去了元模型具有的类型安全。

0