JPA - Criteria API

  • 简述

    Criteria API 是用于定义实体查询的预定义 API。它是定义 JPQL 查询的另一种方式。这些查询是类型安全的、可移植的并且易于通过更改语法进行修改。与 JPQL 类似,它遵循抽象模式(易于编辑模式)和嵌入对象。元数据 API 与标准 API 混合在一起,为标准查询建模持久实体。
    标准 API 的主要优点是可以在编译时更早地检测到错误。基于字符串的 JPQL 查询和基于 JPA 标准的查询在性能和效率上是相同的。
  • 标准 API 的历史

    标准 API 包含在 JPA 的所有版本中,因此标准 API 的每一步都会在 JPA 的规范中进行通知。
    • 在 JPA 2.0 中,标准查询 API、查询的标准化被开发。
    • 在 JPA 2.1 中,包含了 Criteria 更新和删除(批量更新和删除)。
  • 条件查询结构

    Criteria API 和 JPQL 密切相关,允许在其查询中使用类似的运算符进行设计。它遵循 javax.persistence.criteria 包来设计查询。查询结构表示语法标准查询。
    以下简单条件查询返回数据源中实体类的所有实例。
    
    EntityManager em = ...;
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Entity class> cq = cb.createQuery(Entity.class);
    Root<Entity> from = cq.from(Entity.class);
    cq.select(Entity);
    TypedQuery<Entity> q = em.createQuery(cq);
    List<Entity> allitems = q.getResultList();
    
    该查询演示了创建条件的基本步骤。
    • EntityManager实例用于创建CriteriaBuilder对象。
    • CriteriaQuery实例用于创建查询对象。此查询对象的属性将使用查询的详细信息进行修改。
    • 调用CriteriaQuery.from方法来设置查询根。
    • 调用CriteriaQuery.select来设置结果列表类型。
    • TypedQuery<T>实例用于准备执行查询并指定查询结果的类型。
    • TypedQuery<T>对象上的getResultList方法以执行查询。此查询返回一个实体集合,结果存储在一个 List 中。
  • 条件 API 示例

    让我们考虑员工数据库的例子。让我们假设 jpadb.employee 表包含以下记录:
    
    Eid  Ename           Salary   Deg
    401  Gopal             40000  Technical Manager
    402  Manisha           40000  Proof reader
    403  Masthanvali     35000    Technical Writer
    404     Satish         30000  Technical writer
    405  Krishna           30000  Technical Writer
    406  Kiran             35000  Proof reader
    
    在 Eclipse IDE 中创建一个名为的 JPA 项目 JPA_Eclipselink_Criteria. 本项目所有模块如下图所示:

    创建实体

    创建一个名为的包 com.jc2182.eclipselink.entity 在下面 ‘src’ 包裹。
    创建一个名为的类 Employee.java在给定的包下。Employee 类实体如下所示:
    
    package com.jc2182.eclipselink.entity;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    @Entity
    public class Employee {
       @Id
       @GeneratedValue(strategy= GenerationType.AUTO)      
       
       private int eid;
       private String ename;
       private double salary;
       private String deg;
       
       public Employee(int eid, String ename, double salary, String deg) {
          super( );
          this.eid = eid;
          this.ename = ename;
          this.salary = salary;
          this.deg = deg;
       }
       public Employee( ) {
          super();
       }
       public int getEid( ) {
          return eid;
       }
       
       public void setEid(int eid) {
          this.eid = eid;
       }
       public String getEname( ) {
          return ename;
       }
       
       public void setEname(String ename) {
          this.ename = ename;
       }
       public double getSalary( ) {
          return salary;
       }
       
       public void setSalary(double salary) {
          this.salary = salary;
       }
       public String getDeg( ) {
          return deg;
       }
       
       public void setDeg(String deg) {
          this.deg = deg;
       }
       
       @Override
       public String toString() {
       return "Employee [eid = " + eid + ", ename = " + ename + ", salary = " + salary + ", deg = " + deg + "]";
       }
    }
    

    持久化文件

    需要 Persistence.xml 文件来配置数据库和实体类的注册。
    Persistence.xml 将由 Eclipse IDE 在创建 JPA 项目时创建。配置细节是用户规范。persistence.xml 文件如下所示:
    
    <?xml version = "1.0" encoding = "UTF-8"?>
    <persistence version="2.0" xmlns = "http://java.sun.com/xml/ns/persistence" 
       xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance" 
       xsi:schemaLocation = "http://java.sun.com/xml/ns/persistence 
       http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
       
       <persistence-unit name = "Eclipselink_JPA" transaction-type = "RESOURCE_LOCAL">
          <class>com.jc2182.eclipselink.entity.Employee</class>
          
          <properties>
             <property name = "javax.persistence.jdbc.url" value = "jdbc:mysql://localhost:3306/jpadb"/>
             <property name = "javax.persistence.jdbc.user" value = "root"/>
             <property name = "javax.persistence.jdbc.password" value = "root"/>
             <property name = "javax.persistence.jdbc.driver" 
             value="com.mysql.jdbc.Driver"/>
             <property name = "eclipselink.logging.level" value = "FINE"/>
             <property name = "eclipselink.ddl-generation" 
             value="create-tables"/>
          </properties>
          
       </persistence-unit>
    </persistence>
    

    服务类

    该模块包含服务类,它使用元数据 API 初始化实现 Criteria 查询部分。创建一个名为的包‘com.jc2182.eclipselink.service’. 类名为CriteriaAPI.java在给定的包下创建。DAO类如下所示:
    
    package com.jc2182.eclipselink.service;
    import java.util.List;
    import javax.persistence.EntityManager;
    import javax.persistence.EntityManagerFactory;
    import javax.persistence.Persistence;
    import javax.persistence.TypedQuery;
    import javax.persistence.criteria.CriteriaBuilder;
    import javax.persistence.criteria.CriteriaQuery;
    import javax.persistence.criteria.Root;
    import com.jc2182.eclipselink.entity.Employee;
    public class CriteriaApi {
       public static void main(String[] args) {
       
       EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
       EntityManager entitymanager = emfactory.createEntityManager( );
       CriteriaBuilder criteriaBuilder = entitymanager.getCriteriaBuilder();
       CriteriaQuery<Object> criteriaQuery = criteriaBuilder.createQuery();
       Root<Employee> from = criteriaQuery.from(Employee.class);
       //select all records
       System.out.println(“Select all records”);
       CriteriaQuery<Object> select = c riteriaQuery.select(from);
       TypedQuery<Object> typedQuery = entitymanager.createQuery(select);
       List<Object> resultlist = typedQuery.getResultList();
       for(Object o:resultlist) {
          Employee e = (Employee)o;
          System.out.println("EID : " + e.getEid() + " Ename : " + e.getEname());
       }
       //Ordering the records 
       System.out.println(“Select all records by follow ordering”);
       CriteriaQuery<Object> select1 = criteriaQuery.select(from);
       select1.orderBy(criteriaBuilder.asc(from.get("ename")));
       TypedQuery<Object> typedQuery1 = entitymanager.createQuery(select);
       List<Object> resultlist1 = typedQuery1.getResultList();
       for(Object o:resultlist1){
          Employee e=(Employee)o;
          System.out.println("EID : " + e.getEid() + " Ename : " + e.getEname());
       }
       entitymanager.close( );
       emfactory.close( );
       }
    }
    
    编译并执行上述程序后,您将在 Eclipse IDE 的控制台面板中得到如下输出:
    
    Select All records
    EID : 401 Ename : Gopal
    EID : 402 Ename : Manisha
    EID : 403 Ename : Masthanvali
    EID : 404 Ename : Satish
    EID : 405 Ename : Krishna
    EID : 406 Ename : Kiran
    Select All records by follow Ordering
    EID : 401 Ename : Gopal
    EID : 406 Ename : Kiran
    EID : 405 Ename : Krishna
    EID : 402 Ename : Manisha
    EID : 403 Ename : Masthanvali
    EID : 404 Ename : Satish