运营网站需要多少钱,wordpress增加互动,重庆互动网站建设,wordpress上传服务器前些天发现了一个巨牛的人工智能学习网站#xff0c;通俗易懂#xff0c;风趣幽默#xff0c;忍不住分享一下给大家。点击跳转到教程。
JPA的标准查询,名为:JPA criteria查询. 相比JPQL,其优势是类型安全,更加的面向对象.使用标准查询,开发人员可在编译的时候就检查 查询的…
前些天发现了一个巨牛的人工智能学习网站通俗易懂风趣幽默忍不住分享一下给大家。点击跳转到教程。
JPA的标准查询,名为:JPA criteria查询. 相比JPQL,其优势是类型安全,更加的面向对象.使用标准查询,开发人员可在编译的时候就检查 查询的正确与否.
相关资料Hibernate
org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor
http://relation.to/Bloggers/HibernateStaticMetamodelGeneratorAnnotationProcessorOpenJPA
org.apache.openjpa.persistence.meta.AnnotationProcessor6
http://openjpa.apache.org/builds/latest/docs/manual/manual.html#d0e11094DataNucleus
org.datanucleus.jpa.JPACriteriaProcessor
http://www.datanucleus.org/products/accessplatform_2_1/jpa/jpql_criteria_metamodel.html
一.JPA元模型概念,及使用
在JPA中,标准查询是以元模型的概念为基础的.元模型是为具体持久化单元的受管实体定义的.这些实体可以是实体类,嵌入类或者映射的父类.提供受管实体元信息的类就是元模型类.
描述受管类的状态和他们之间的关系的静态元模型类可以
1.从注解处理器产生2.从程序产生3.用EntityManager访问.
如下code,一个简单的实体类package com.demo.entities;下,实体类Employee 假设该实体有诸如idname和age的基本属性还有与类Address的OneToMany关联:
Entity
Table
public class Employee{ private int id; private String name;private int age;OneToManyprivate ListAddress addresses;// Other code…
}
Employee类(com.demo.entities包中定义)的标准元模型类的名字将是使用 javax.persistence.StaticMetamodel注解的Employee_。元模型类的属性全部是static和public的。Employee的每一个属性都会使用在JPA2规范中描述的以下规则在相应的元模型类中映射
诸如idname和age的非集合类型会定义静态属性SingularAttributeA, B b这里b是定义在类A中的类型为B的一个对象。对于Addess这样的集合类型会定义静态属性ListAttributeA, B b这里List对象b是定义在类A中类型B的对象。其它集合类型可以是SetAttribute, MapAttribute 或 CollectionAttribute 类型。以下是用注解处理器产生的元模型类package com.demo.entities;下
import javax.annotation.Generated;
import javax.persistence.metamodel.SingularAttribute;
import javax.persistence.metamodel.ListAttribute;
import javax.persistence.metamodel.StaticMetamodel;
Generated(org.hibernate.jpamodelgen.JPAMetaModelEntityProcesso)
StaticMetamodel(Employee.class)
public class Employee_ { public static volatile SingularAttributeEmployee, Integer id; public static volatile SingularAttributeEmployee, Integer age; public static volatile SingularAttributeEmployee, String name; public static volatile ListAttributeEmployee, Address addresses;
}
就像它的名字表明的注解处理器处理注解帮助产生源代码。注解处理在编译时就能激活。元模型类遵循JPA2.0规范中为定义标准元模型类而描述的规则创建。
使用元模型类最大的优势是凭借其实例化可以在编译时访问实体的持久属性.该特性使得criteria 查询更加类型安全.
元模型API与Java中的标准反射API密切相关。主要不同在于使用标准反射API编译器无法验证其正确性。例如下面的代码会通过编译测试
Class myClass Class.forName(com.demo.Test);
Field myField myClass.getField(myName);
编译器假定com.demo.Test中定义了属性myName一旦该类并没有定义属性myName编译器将抛出运行时异常。
元模型API会强制编译器检查适当的值是否分配给实体类的持久属性。例如考虑Employee类的age属性它是Integer变量。若该属性被赋值为String类型的值编译器会抛出错误。该实现并不要求支持非标准特性。程序员编写的元模型类通常称为非标准元模型类。当EntityManagerFactory 创建时持久化提供者会初始化元模型类的属性。
二.使用criteria 查询简单Demo
为了更好的理解criteria 查询考虑拥有Employee实例集合的Dept实体Employee和Dept的元模型类的代码如下
//All Necessary Imports
StaticMetamodel(Dept.class)
public class Dept_ { public static volatile SingularAttributeDept, Integer id; public static volatile ListAttributeDept, Employee employeeCollection; public static volatile SingularAttributeDept, String name;
}
//All Necessary Imports
StaticMetamodel(Employee.class)
public class Employee_ { public static volatile SingularAttributeEmployee, Integer id; public static volatile SingularAttributeEmployee, Integer age; public static volatile SingularAttributeEmployee, String name; public static volatile SingularAttributeEmployee, Dept deptId;
}
下面的代码片段展示了一个criteria 查询它用于获取所有年龄大于24岁的员工
CriteriaBuilder criteriaBuilder em.getCriteriaBuilder();
CriteriaQueryEmployee criteriaQuery criteriaBuilder.createQuery(Employee.class);
RootEmployee employee criteriaQuery.from(Employee.class);
Predicate condition criteriaBuilder.gt(employee.get(Employee_.age), 24);
criteriaQuery.where(condition);
TypedQueryEmployee typedQuery em.createQuery(criteriaQuery);
ListEmployee result typedQuery.getResultList();
对应的SQL: SELECT * FROM employee WHERE age 24
三.构建CriteriaQuery 实例API说明
1.CriteriaBuilder 安全查询创建工厂,创建CriteriaQuery,创建查询具体具体条件Predicate 等
CriteriaBuilder是一个工厂对象,安全查询的开始.用于构建JPA安全查询.可以从EntityManager 或 EntityManagerFactory类中获得CriteriaBuilder. 比如: CriteriaBuilder criteriaBuilder em.getCriteriaBuilder();
2.CriteriaQuery 安全查询主语句
CriteriaQuery对象必须在实体类型或嵌入式类型上的Criteria 查询上起作用。 它通过调用 CriteriaBuilder, createQuery 或CriteriaBuilder.createTupleQuery 获得。 CriteriaBuilder就像CriteriaQuery 的工厂一样。 CriteriaBuilder工厂类是调用EntityManager.getCriteriaBuilder 或 EntityManagerFactory.getCriteriaBuilder而得。 Employee实体的 CriteriaQuery 对象以下面的方式创建
CriteriaBuilder criteriaBuilder em.getCriteriaBuilder();
CriteriaQueryEmployee criteriaQuery criteriaBuilder.createQuery(Employee.class);
3.Root 定义查询的From子句中能出现的类型
AbstractQuery是CriteriaQuery 接口的父类。它提供得到查询根的方法。 Criteria查询的查询根定义了实体类型能为将来导航获得想要的结果它与SQL查询中的FROM子句类似。 Root实例也是类型化的且定义了查询的FROM子句中能够出现的类型。 查询根实例能通过传入一个实体类型给 AbstractQuery.from方法获得。 Criteria查询可以有多个查询根。 Employee实体的查询根对象可以用以下的语法获得
RootEmployee employee criteriaQuery.from(Employee.class);
4.Predicate 过滤条件
过滤条件应用到SQL语句的FROM子句中。 在criteria 查询中查询条件通过Predicate 或Expression 实例应用到CriteriaQuery 对象上。 这些条件使用 CriteriaQuery .where 方法应用到CriteriaQuery 对象上。 CriteriaBuilder 也是作为Predicate 实例的工厂Predicate 对象通过调用CriteriaBuilder 的条件方法 equalnotEqual gt gelt lebetweenlike等创建。 Predicate 实例也可以用Expression 实例的 isNull isNotNull 和 in方法获得复合的Predicate 语句可以使用CriteriaBuilder的and, or andnot 方法构建。 下面的代码片段展示了Predicate 实例检查年龄大于24岁的员工实例:
Predicate condition criteriaBuilder.gt(employee.get(Employee_.age), 24);
criteriaQuery.where(condition);
过Employee_元模型类age属性称之为路径表达式。若age属性与String文本比较编译器会抛出错误这在JPQL中是不可能的。
5.Predicate[] 多个过滤条件
ListPredicate predicatesList new ArrayListPredicate();
predicatesList.add(.....Pridicate....)
criteriaQuery.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
OR语句
predicatesList.add(criteriaBuilder.or(criteriaBuilder.equal(root.get(RepairOrder_.localRepairStatus), LocalRepairStatus.repairing),criteriaBuilder.equal(root.get(RepairOrder_.localRepairStatus), LocalRepairStatus.diagnos)));
忽略大小写(全大写)
predicatesList.add(criteriaBuilder.like(criteriaBuilder.upper(root.get(RepairShop_.shopName)), StringUtils.upperCase(StringUtils.trim(this.shopName)) %));
通过如上两句添加多个.
6.TypedQuery执行查询与获取元模型实例
注意你使用EntityManager创建查询时可以在输入中指定一个CriteriaQuery对象它返回一个TypedQuery它是JPA 2.0引入javax.persistence.Query接口的一个扩展TypedQuery接口知道它返回的类型。
所以使用中,先创建查询得到TypedQuery,然后通过typeQuery得到结果.
当EntityManager.createQuery(CriteriaQuery)方法调用时一个可执行的查询实例会创建该方法返回指定从 criteria 查询返回的实际类型的TypedQuery 对象。
TypedQuery 接口是javax.persistence.Queryinterface.的子类型。在该片段中 TypedQuery 中指定的类型信息是Employee调用getResultList时查询就会得到执行 TypedQueryEmployee typedQuery em.createQuery(criteriaQuery); ListEmployee result typedQuery.getResultList(); 元模型实例通过调用 EntityManager.getMetamodel 方法获得EntityTypeEmployee的元模型实例通过调用Metamodel.entity(Employee.class)而获得其被传入 CriteriaQuery.from 获得查询根。
Metamodel metamodel em.getMetamodel();EntityTypeEmployee
Employee_ metamodel.entity(Employee.class);
RootEmployee empRoot criteriaQuery.from(Employee_);
也有可能调用Root.getModel方法获得元模型信息。类型 EntityTypeDept的实例Dept_和name属性可以调用getSingularAttribute 方法获得它与String文本进行比较 CriteriaQuery criteriaQuery criteriaBuilder.createQuery();
RootDept dept criteriaQuery.from(Dept.class);
EntityTypeDept Dept_ dept.getModel();
Predicate testCondition criteriaBuilder.equal(dept.get(Dept_.getSingularAttribute(name, String.class)), Ecomm);
7.Expression 用在查询语句的selectwhere和having子句中该接口有 isNull, isNotNull 和 in方法
Expression对象用在查询语句的selectwhere和having子句中该接口有 isNull, isNotNull 和 in方法下面的代码片段展示了Expression.in的用法employye的年龄检查在20或24的。
CriteriaQueryEmployee criteriaQuery criteriaBuilder .createQuery(Employee.class);
RootEmployee 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)
下面也是一个更贴切的例子:
//定义一个Expression
ExpressionString exp root.get(Employee.id);
//
ListString strListnew ArrayList();
strList.add(20);
strList.add(24);
predicatesList.add(exp.in(strList));criteriaQuery.where(predicatesList.toArray(new Predicate[predicatesList.size()]));
8.复合谓词
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中连接跨多张表以获取查询结果类似的实体连接通过调用 From.join 执行连接帮助从一个实体导航到另一个实体以获得查询结果。 Root的join方法返回一个 JoinDept, Employee类型(也可以是SetJoin,ListJoinMapJoin 或者 CollectionJoin类型)。
默认情况下连接操作使用内连接而外连接可以通过在join方法中指定JoinType参数为LEFT或RIGHT来实现。
CriteriaQueryDept cqDept criteriaBuilder.createQuery(Dept.class);
RootDept deptRoot cqDept.from(Dept.class);
JoinDept, Employee employeeJoin deptRoot.join(Dept_.employeeCollection);
cqDept.where(criteriaBuilder.equal(employeeJoin.get(Employee_.deptId).get(Dept_.id), 1));
TypedQueryDept resultDept em.createQuery(cqDept);
抓取连接
当涉及到collection属性时抓取连接对优化数据访问是非常有帮助的。这是通过预抓取关联对象和减少懒加载开销而达到的。 使用 criteria 查询fetch方法用于指定关联属性 Fetch连接的语义与Join是一样的因为Fetch操作不返回Path对象所以它不能将来在查询中引用。 在以下例子中查询Dept对象时employeeCollection对象被加载这不会有第二次查询数据库因为有懒加载。
CriteriaQueryDept d cb.createQuery(Dept.class);
RootDept deptRoot d.from(Dept.class);
deptRoot.fetch(employeeCollection, JoinType.LEFT);
d.select(deptRoot);
ListDept 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方法。例子如下 CriteriaQueryString criteriaQuery criteriaBuilder.createQuery(String.class);
RootDept root criteriaQuery.from(Dept.class);
criteriaQuery.select(root.get(Dept_.name));nbsp;
参数化表达式 在JPQL中查询参数是在运行时通过使用命名参数语法(冒号加变量如 :age)传入的。在Criteria查询中查询参数是在运行时创建ParameterExpression对象并为在查询前调用TypeQuery,setParameter方法设置而传入的。下面代码片段展示了类型为Integer的ParameterExpression age它被设置为24 ParameterExpressionInteger age criteriaBuilder.parameter(Integer.class);
Predicate condition criteriaBuilder.gt(testEmp.get(Employee_.age), age);
criteriaQuery.where(condition);
TypedQueryEmployee testQuery em.createQuery(criteriaQuery);
ListEmployee result testQuery.setParameter(age, 24).getResultList();
Corresponding SQL: SELECT * FROM Employee WHERE age 24;
排序结果 Criteria查询的结果能调用CriteriaQuery.orderBy方法排序该方法接收一个Order对象做为参数。通过调用 CriteriaBuilder.asc 或 CriteriaBuilder.DescOrder对象能被创建。以下代码片段中Employee实例是基于age的升序排列。 CriteriaQueryEmployee criteriaQuery criteriaBuilder .createQuery(Employee.class);RootEmployee 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开头 CriteriaQueryTuple cq criteriaBuilder.createQuery(Tuple.class); RootEmployee 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)));TypedQueryTuple q em.createQuery(cq);ListTuple result q.getResultList();
对应 SQL: SELECT name, COUNT(*) FROM employeeGROUP BY name HAVING name like N% 查询投影
Criteria查询的结果与在Critiria查询创建中指定的一样。结果也能通过把查询根传入 CriteriaQuery.select中显式指定。Criteria查询也给开发者投影各种结果的能力。
使用construct()
使用该方法查询结果能由非实体类型组成。在下面的代码片段中为EmployeeDetail类创建了一个Criteria查询对象而EmployeeDetail类并不是实体类型。 CriteriaQueryEmployeeDetails criteriaQuery criteriaBuilder.createQuery(EmployeeDetails.class);RootEmployee 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 employeespan stylewhite-space: normal;nbsp;/span 返回Object[]的查询
Criteria查询也能通过设置值给CriteriaBuilder.array方法返回Object[]的结果。下面的代码片段中数组大小是2由String和Integer组成。 CriteriaQueryObject[] criteriaQuery criteriaBuilder.createQuery(Object[].class);RootEmployee 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方法传入参数它必须在查询中返回。 CriteriaQueryTuple criteriaQuery criteriaBuilder.createTupleQuery();RootEmployee 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。 转自https://my.oschina.net/zhaoqian/blog/133500