该文翻译自网络,原文地址:
JPA流行的主要原因之一是JPQL,它支持面向对象的机制来查询数据库。但是JPQL有一个重大缺陷:作为查询字符串构建的JPQL查询在编译时不会被计算。JPA2.0引入了criteria 查询:一种类型安全和更面向对象的查询。使用criteria 查询,开发人员可以在编译时检查查询的正确与否。该特性以前只在像Hibernate这样的某些专用框架中可用。
在本文中,我将解释criteria 查询,并且浏览对构建criteria 查询非常有必要的元模型(metamodel)的概念。另外也会讨论criteria 查询的各种API。
元模型概念
在JPA2.0中,criteria 查询是以元模型的概念为基础的,元模型是为具体持久化单元的受管实体定义的,这些实体可以是实体类,嵌入类或者映射的父类。简答点说,提供受管实体元信息的类就是元模型类。描述受管类的状态和它们之间的关系的静态元模型类可以:
l 从注解处理器产生
l 从程序产生
l 用EntityManager访问
考虑定义在包com.demo.entities中的实体类Employee
,假设该实体有诸如id,name和age的基本属性,还有与类Address的OneToMany关联。
package com.demo.entities;
@Entity @Table public class Employee{ private int id; private String name; private int age; @OneToMany private List<Address> addresses; // Other code… }
Employee类(com.demo.entities
包中定义)的标准元模型类的名字将是使用 javax.persistence.StaticMetamodel
注解的
Employee_。元模型类的属性全部是static和public的。Employee的每一个属性都会使用在JPA2规范中描述的以下规则在相应的元模型类中映射:
l 诸如id,name和age的非集合类型,会定义静态属性SingularAttribute<A, B> b,这里b是定义在类A中的类型为B的一个对象。
l 对于Addess这样的集合类型,会定义静态属性ListAttribute<A, 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("EclipseLink-2.1.0.v20100614-r7608 @ Tue Jul 27 10:13:02 IST 2010") @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 ListAttribute<Employee, 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
创建时,持久化提供者会初始化元模型类的属性。
(未待续完)