JPA2中的查询:类型安全与面向对象(2)
该文翻译自网络,原文地址:
http://www.developer.com/java/ent/article.php/3902911/Querying-in-JPA-2-Typesafe-and-Object-Oriented.htm
为了更好的理解criteria 查询,考虑拥有Employee实例集合的Dept实体,Employee和Dept的元模型类的代码如下:
?
//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?对象必须在实体类型或嵌入式类型上的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);?
?
?
?
?
AbstractQuery是CriteriaQuery?接口的父类。它提供得到查询根的方法。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?的条件方法(?equal,notEqual,?gt,?ge,lt,?le,between,like等)创建。Predicate?实例也可以用Expression?实例的?isNull,?isNotNull?和?in方法获得,复合的Predicate?语句可以使用CriteriaBuilder的and,?or?andnot?方法构建。
Predicate condition = criteriaBuilder.gt(employee.get(Employee_.age), 24);criteriaQuery.where(condition);
当EntityManager.createQuery(CriteriaQuery)方法调用时,一个可执行的查询实例会创建,该方法返回指定从?criteria查询返回的实际类型的TypedQuery?对象。TypedQuery?接口是javax.persistence.Queryinterface.的子类型。在该片段中, TypedQuery?中指定的类型信息是Employee,调用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对象用在查询语句的select,where和having子句中,该接口有?isNull,?isNotNull?和?in方法,下面的代码片段展示了Expression.in的用法,employye的年龄检查在20或24的。
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开头,其次,employee的age属性是否是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%' ANDage = 25
在SQL中,连接跨多张表以获取查询结果,类似的实体连接通过调用?From.join?执行,连接帮助从一个实体导航到另一个实体以获得查询结果。
Root的join方法返回一个?Join<Dept, Employee>类型(也可以是SetJoin,,ListJoin,MapJoin?或者?CollectionJoin类型)。默认情况下,连接操作使用内连接,而外连接可以通过在join方法中指定JoinType参数为LEFT或RIGHT来实现。
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
?
2 楼 qianli 2012-02-07 为何entityManager.getCriteriaBuilder()为空呢?