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

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

阅读更多

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

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

使用criteria 查询

为了更好的理解criteria 查询,考虑拥有Employee实例集合的Dept实体,EmployeeDept的元模型类的代码如下:

 

//All Necessary Imports
@StaticMetamodel(Dept.class)
public class Dept_ {    
	public static volatile SingularAttribute<Dept, Integer> id;   
	public static volatile ListAttribute<Dept, Employee> employeeCollection;    
	public static volatile SingularAttribute<Dept, String> name;
}
//All Necessary Imports
@StaticMetamodel(Employee.class)
public class Employee_ {     
	public static volatile SingularAttribute<Employee, Integer> id;    
	public static volatile SingularAttribute<Employee, Integer> age;    
	public static volatile SingularAttribute<Employee, String> name;    
	public static volatile SingularAttribute<Employee, Dept> deptId;
}

下面的代码片段展示了一个criteria 查询,它用于获取所有年龄大于24岁的员工:

 

CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = criteriaBuilder.createQuery(Employee.class);
Root<Employee> employee = criteriaQuery.from(Employee.class);
Predicate condition = criteriaBuilder.gt(employee.get(Employee_.age), 24);
criteriaQuery.where(condition);
TypedQuery<Employee> typedQuery = em.createQuery(criteriaQuery);
List<Employee> result = typedQuery.getResultList();

 

 对应的SQL: SELECT * FROM employee WHERE age > 24

 

构建CriteriaQuery 实例

CriteriaQuery 对象必须在实体类型或嵌入式类型上的Criteria 查询上起作用。它通过调用 CriteriaBuilder, createQuery CriteriaBuilder.createTupleQuery 获得。CriteriaBuilder就像CriteriaQuery 的工厂一样。CriteriaBuilder工厂类是调用EntityManager.getCriteriaBuilder  EntityManagerFactory.getCriteriaBuilder而得。 Employee实体的 CriteriaQuery 对象以下面的方式创建:

 

CriteriaBuilder criteriaBuilder = emf.getCriteriaBuilder();
CriteriaQuery<Employee> criteriaQuery = cb.createQuery(Employee.class);
 

 

 

 

 

QueryRoot

AbstractQueryCriteriaQuery 接口的父类。它提供得到查询根的方法。Criteria查询的查询根定义了实体类型,能为将来导航获得想要的结果,它与SQL查询中的FROM子句类似。

Root实例也是类型化的,且定义了查询的FROM子句中能够出现的类型。查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。Criteria查询,可以有多个查询根。Employee实体的查询根对象可以用以下的语法获得: 

 

Root<Employee> employee = criteriaQuery.from(Employee.class);

 过滤Queries

 

过滤条件应用到SQL语句的FROM子句中。在criteria 查询中,查询条件通过Predicate Expression 实例应用到CriteriaQuery 对象上。这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上。CriteriaBuilder 也是作为Predicate 实例的工厂,Predicate 对象通过调用CriteriaBuilder 的条件方法( equalnotEqual gt gelt lebetweenlike等)创建。Predicate 实例也可以用Expression 实例的 isNull isNotNull  in方法获得,复合的Predicate 语句可以使用CriteriaBuilderand, or andnot 方法构建。

下面的代码片段展示了Predicate 实例检查年龄大于24岁的员工实例

Predicate condition = criteriaBuilder.gt(employee.get(Employee_.age), 24);
criteriaQuery.where(condition);

 通过Employee_元模型类age属性,称之为路径表达式。若age属性与String文本比较,编译器会抛出错误,这在JPQL中是不可能的。

执行查询与获取元模型实例

EntityManager.createQuery(CriteriaQuery)方法调用时,一个可执行的查询实例会创建,该方法返回指定从 criteria 查询返回的实际类型的TypedQuery 对象。TypedQuery 接口是javax.persistence.Queryinterface.的子类型。在该片段中, TypedQuery 中指定的类型信息是Employee,调用getResultList时,查询就会得到执行 

TypedQuery<Employee> typedQuery = em.createQuery(criteriaQuery);

List<Employee> result = typedQuery.getResultList();

元模型实例通过调用 EntityManager.getMetamodel 方法获得,EntityType<Employee>的元模型实例通过调用Metamodel.entity(Employee.class)而获得,其被传入 CriteriaQuery.from 获得查询根。

Metamodel metamodel = em.getMetamodel();EntityType<Employee> 
Employee_ = metamodel.entity(Employee.class);
Root<Employee> empRoot = criteriaQuery.from(Employee_);

 也有可能调用Root.getModel方法获得元模型信息。类型 EntityType<Dept>的实例Dept_name属性可以调用getSingularAttribute 方法获得,它与String文本进行比较:

CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root<Dept> dept = criteriaQuery.from(Dept.class);
EntityType<Dept> Dept_ = dept.getModel();
Predicate testCondition = criteriaBuilder.equal(dept.get(Dept_.getSingularAttribute("name", String.class)), "Ecomm");

 对应的 SQL: SELECT * FROM dept WHERE name = 'Ecomm'

Expression

Expression对象用在查询语句的selectwherehaving子句中,该接口有 isNull, isNotNull  in方法,下面的代码片段展示了Expression.in的用法,employye的年龄检查在2024的。

CriteriaQuery<Employee> criteriaQuery = criteriaBuilder .createQuery(Employee.class);
Root<Employee> employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(employee.get(Employee_.age).in(20, 24));
em.createQuery(criteriaQuery).getResultList();

 对应的SQL: SELECT * FROM employee WHERE age in (20, 24)

复合谓词

Criteria Query也允许开发者编写复合谓词,通过该查询可以为多条件测试下面的查询检查两个条件。首先,name属性是否以M开头,其次,employeeage属性是否是25。逻辑操作符and执行获得结果记录。

criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.like(employee.get(Employee_.name), "M%"), criteriaBuilder.equal(employee.get(Employee_.age), 25)));
em.createQuery(criteriaQuery).getResultList();

 对应 SQL: SELECT * FROM employee  WHERE name LIKE 'M%' AND age = 25

连接查询

SQL中,连接跨多张表以获取查询结果,类似的实体连接通过调用 From.join 执行,连接帮助从一个实体导航到另一个实体以获得查询结果。

Rootjoin方法返回一个 Join<Dept, Employee>类型(也可以是SetJoin,ListJoinMapJoin 或者 CollectionJoin类型)。默认情况下,连接操作使用内连接,而外连接可以通过在join方法中指定JoinType参数为LEFTRIGHT来实现。

CriteriaQuery<Dept> cqDept = criteriaBuilder.createQuery(Dept.class);
Root<Dept> deptRoot = cqDept.from(Dept.class);
Join<Dept, Employee> employeeJoin = deptRoot.join(Dept_.employeeCollection);
cqDept.where(criteriaBuilder.equal(employeeJoin.get(Employee_.deptId).get(Dept_.id), 1));
TypedQuery<Dept> resultDept = em.createQuery(cqDept);
 对应的SQL: SELECT * FROM employee e, dept d  WHERE e.deptId = d.id and d.id = 1

 

5
4
分享到:
评论
6 楼 我爱吃酥饼 2017-07-07  
u012014301 写道
请问下Dept_这个类是要自己手动创建 还是可以根据实体类或者配置文件自动生成啊?



自动生产,eclipse和idea ide 工具,需要配置,具体的你可以加我qq522450654
5 楼 u012014301 2017-06-08  
请问下Dept_这个类是要自己手动创建 还是可以根据实体类或者配置文件自动生成啊?
4 楼 jiangli19192 2014-05-29  
请问Dept_.employeeCollection里面的Dept_从哪里来的
3 楼 307622798 2013-03-04  
讲解的很详细,谢谢,帮我解决了一个大问题!
2 楼 qianli 2012-02-07  
为何entityManager.getCriteriaBuilder()为空呢?
1 楼 寒光2008 2011-07-20  
引用

相关推荐

Global site tag (gtag.js) - Google Analytics