该文翻译自网络,原文地址:
抓取连接
当涉及到collection属性时,抓取连接对优化数据访问是非常有帮助的。这是通过预抓取关联对象和减少懒加载开销而达到的。使用 criteria 查询,fetch方法用于指定关联属性
Fetch连接的语义与Join是一样的,因为Fetch操作不返回Path对象,所以它不能将来在查询中引用。在以下例子中,查询Dept对象时employeeCollection对象被加载,这不会有第二次查询数据库,因为有懒加载。
CriteriaQuery<Dept> d = cb.createQuery(Dept.class); Root<Dept> deptRoot = d.from(Dept.class); deptRoot.fetch("employeeCollection", JoinType.LEFT); d.select(deptRoot); List<Dept> dList = em.createQuery(d).getResultList();
对应SQL: SELECT * FROM dept d, employee e WHERE d.id = e.deptId
路径表达式
Root实例,Join实例或者从另一个Path对象的get方法获得的对象使用get方法可以得到Path对象,当查询需要导航到实体的属性时,路径表达式是必要的。Get方法接收的参数是在实体元模型类中指定的属性。Path对象一般用于Criteria查询对象的select或where方法。例子如下:
CriteriaQuery<String> criteriaQuery = criteriaBuilder.createQuery(String.class); Root<Dept> root = criteriaQuery.from(Dept.class); criteriaQuery.select(root.get(Dept_.name));
参数化表达式
在JPQL中,查询参数是在运行时通过使用命名参数语法(冒号加变量,如 :age)传入的。在Criteria查询中,查询参数是在运行时创建ParameterExpression对象并为在查询前调用TypeQuery,setParameter方法设置而传入的。下面代码片段展示了类型为Integer的ParameterExpression age,它被设置为24:
ParameterExpression<Integer> age = criteriaBuilder.parameter(Integer.class); Predicate condition = criteriaBuilder.gt(testEmp.get(Employee_.age), age); criteriaQuery.where(condition); TypedQuery<Employee> testQuery = em.createQuery(criteriaQuery); List<Employee> result = testQuery.setParameter(age, 24).getResultList(); Corresponding SQL: SELECT * FROM Employee WHERE age = 24
排序结果
Criteria查询的结果能调用CriteriaQuery.orderBy方法排序,该方法接收一个Order对象做为参数。通过调用 CriteriaBuilder.asc 或 CriteriaBuilder.Desc,Order对象能被创建。以下代码片段中,Employee实例是基于age的升序排列。
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder .createQuery(Employee.class); Root<Employee> employee = criteriaQuery.from(Employee.class); criteriaQuery.orderBy(criteriaBuilder.asc(employee.get(Employee_.age))); em.createQuery(criteriaQuery).getResultList();
对应 SQL: SELECT * FROM Employee ORDER BY age ASC
分组
CriteriaQuery 实例的groupBy 方法用于基于Expression的结果分组。查询通过设置额外表达式,以后调用having方法。下面代码片段中,查询按照Employee类的name属性分组,且结果以字母N开头:
CriteriaQuery<Tuple> cq = criteriaBuilder.createQuery(Tuple.class);
Root<Employee> employee = cq.from(Employee.class); cq.groupBy(employee.get(Employee_.name)); cq.having(criteriaBuilder.like(employee.get(Employee_.name), "N%")); cq.select(criteriaBuilder.tuple(employee.get(Employee_.name),criteriaBuilder.count(employee))); TypedQuery<Tuple> q = em.createQuery(cq); List<Tuple> result = q.getResultList();
对应 SQL: SELECT name, COUNT(*) FROM employeeGROUP BY name HAVING name like 'N%'
查询投影
Criteria查询的结果与在Critiria查询创建中指定的一样。结果也能通过把查询根传入 CriteriaQuery.select中显式指定。Criteria查询也给开发者投影各种结果的能力。
使用construct()
使用该方法,查询结果能由非实体类型组成。在下面的代码片段中,为EmployeeDetail类创建了一个Criteria查询对象,而EmployeeDetail类并不是实体类型。
CriteriaQuery<EmployeeDetails> criteriaQuery = criteriaBuilder.createQuery(EmployeeDetails.class);
Root<Employee> employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.construct(EmployeeDetails.class, employee.get(Employee_.name), employee.get(Employee_.age)));
em.createQuery(criteriaQuery).getResultList();
Corresponding SQL: SELECT name, age FROM employee
返回Object[]的查询
Criteria查询也能通过设置值给CriteriaBuilder.array方法返回Object[]的结果。下面的代码片段中,数组大小是2(由String和Integer组成)。
CriteriaQuery<Object[]> criteriaQuery = criteriaBuilder.createQuery(Object[].class); Root<Employee> employee = criteriaQuery.from(Employee.class); criteriaQuery.select(criteriaBuilder.array(employee.get(Employee_.name), employee.get(Employee_.age))); em.createQuery(criteriaQuery).getResultList();
对应 SQL: SELECT name, age FROM employee
返回元组(Tuple)的查询
数据库中的一行数据或单个记录通常称为元组。通过调用CriteriaBuilder.createTupleQuery()方法,查询可以用于元组上。CriteriaQuery.multiselect方法传入参数,它必须在查询中返回。
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery(); Root<Employee> employee = criteriaQuery.from(Employee.class); criteriaQuery.multiselect(employee.get(Employee_.name).alias("name"), employee.get(Employee_.age).alias("age")); em.createQuery(criteriaQuery).getResultList();
对应 SQL: SELECT name, age FROM employee
结论
Criteria 查询是一种以更加面向对象的方式查询数据库的方法、在本文中,我讨论了 JPA2 中类型安全的 Criteria 查询,以及对于理解 Criteria 查询非常重要的元模型的概念。也讨论了 Criteria 查询中的各种 API 。
(完)