`
tanlan
  • 浏览: 202163 次
  • 性别: Icon_minigender_1
  • 来自: 成都
社区版块
存档分类
最新评论

JPA2中的查询:类型安全与面向对象(3)

阅读更多

该文翻译自网络,原文地址:

http://www.developer.com/java/ent/article.php/3902911/Querying-in-JPA-2-Typesafe-and-Object-Oriented.htm

抓取连接

当涉及到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查询对象的selectwhere方法。例子如下:

 

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方法设置而传入的。下面代码片段展示了类型为IntegerParameterExpression 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.DescOrder对象能被创建。以下代码片段中,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(由StringInteger组成)。

 

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

 

 

(完)

4
2
分享到:
评论
3 楼 hesai_vip 2014-03-03  
java.sql.SQLException: ORA-00979: 不是 GROUP BY 表达式

public static Specification<DfOperationCorrection> testDfoc(final Collection<Filter> filters) {
return new Specification<DfOperationCorrection>() {
@Override
public Predicate toPredicate(Root<DfOperationCorrection> root,
CriteriaQuery<?> query, CriteriaBuilder builder) {
Predicate pc = null;
root = query.from(DfOperationCorrection.class);
query.groupBy(root.get("applicationNo"));
pc = query.getGroupRestriction();

return pc;
}
};
}
2 楼 hesai_vip 2014-03-03  
mark一下。感觉使用分组.groupBy时无效。
1 楼 liuxiang00435057 2012-12-21  
我的分组统计是这样做的,但是红色部分不起作用
public List<Ulproduct> findAll(String username) {
List<Ulproduct> pageProducts = ulproductDao
.findAll(queryAllByMutiCondition(username));
return pageProducts;
}

private  Specification<Ulproduct> queryAllByMutiCondition(
final String username) {
return new Specification<Ulproduct>() {

@Override
public Predicate toPredicate(Root<Ulproduct> p,
CriteriaQuery<?> q, CriteriaBuilder cb) {
//q = cb.createQuery(Ulproduct.class);
p = q.from(Ulproduct.class);
q.groupBy(p.get("productsname"));

q.multiselect(p.<String>get("productsname"),
cb.sum(p.<Integer> get("stocksnum")),
cb.sum(p.<Double> get("price")),
cb.sum(p.<Double> get("cost")));


q.where(cb.equal(p.<String>get("username"),
StringUtils.trim(username)));

return q.getGroupRestriction();
}
};
}

相关推荐

Global site tag (gtag.js) - Google Analytics