2011年4月18日 星期一

Metamodel and JPQL (dynamic query)

[Metamodel API]

* 將 metamodel class 定義為 持久化實體類的描述。
就像 Reflection API 需要其他接口(比如 java.lang.reflect.Field 或 java.lang.reflect.Method)來描述 java.lang.Class 的组成一樣,JPA Metamodel API 也需要其他接口(比如 SingularAttribute 和 PluralAttribute)來描述元模型类的类型及其属性。

* 持久化实体在语义上区分为 MappedSuperClass、Entity 和 Embeddable
在 JPA 2.0 之前,这种语义区分是通过持久化类定义中的对应类级别注释来表示的


* JPA Metamodel 在 javax.persistence.metamodel 包中描述了 3 个独立的接口:
  • MappedSuperclassType
  • EntityType
  • EmbeddableType
类似地,可以通过接口(比如 SingularAttribute、CollectionAttribute 和 MapAttribute)在类型定义级别上区分持久化属性。

* 持久化单元作用域的持久化实体在 META-INF/persistence.xml 文件的 <class> 子句中枚举。
通过 javax.persistence.metamodel.Metamodel 接口让开发人员可以在运行时使用作用域。Metamodel 接口是特定持久化单元知道的所有持久化实体的容器。

* 元模型接口是持久化单元中的类型的容器。

* 这个接口允许通过元模型元素的对应持久化实体类访问元模型元素。

* 可以在运行时浏览 EntityType<person> 获得在 Person 实体中声明的持久化属性

* 如果应用程序在 pClass(比如 pClass.getSingularAttribute("age", Integer.class))上调用一个方法,它将返回一个 SingularAttribute<person, integer=""> 实例,该实例与实例化规范元模型类的静态 Person_.age 成员相同

* 最重要的是,对于应用程序可以通过 Metamodel API 在运行时引用的属性,是通过实例化静态规范元模型 Person_ 类向 Java 编译器提供的。

* 除了将持久化实体分解为对应的元模型元素之外,Metamodel API 还允许访问所有已知的元模型类 (Metamodel.getManagedTypes()),或者通过类的持久化信息访问元模型类,例如 embeddable(Address.class),它将返回一个 EmbeddableType<address> 实例(ManagedType<> 的子接口)。

* 持久化元信息分为两大类:
  • 持久化, ex: @Entity
    • 元模型仅为持久化注释(不是映射注释)捕捉元数据。因此,使用当前版本的 Metamodel API 可以知道哪些字段是持久化的,但不能找到它们映射到的数据库列。
  • 映射, ex: @Table
* Person_.age
  • 表示 Person 的持久化属性 age。
  • 是 Person_ 类中的公共静态字段,Person_ 是静态、已实例化的规范元模型类,对应于原来的 Person 实体类。
* 元模型类描述持久化类的元数据。如果一个类安装 JPA 2.0 规范精确地描述持久化实体的元数据,那么该元模型类就是规范的。
  • 规范的元模型类是静态的,因此它的所有成员变量都被声明为静态的(也是 public 的)。
  • Person_.age 是静态成员变量之一。您可以在开发时在源代码中生成一个具体的 Person_.java 来实例化 一个规范类。
  • 实例化之后,它就可以在编译期间以强类型的方式引用 Person 的持久化属性。

* JPA 2.0 提供的解决办法通过静态地公开相同的持久化属性实例化名为 Person_ 的元模型类(对应于 Person)。
  • 元模型类将原来的 domain.Person 实体的每个持久化属性声明为类型为 SingularAttribute< Person,?> 的静态公共字段。
  • 通过利用这个 Person_ 元模型类,可以在编译期间引用 domain.Person 的持久化属性 age — 不是通过 Reflection API,而是直接引用静态的 Person_.age 字段
  • 编译器可以根据 age 属性声明的类型实施类型检查。
  • ex:QueryBuilder.gt(p.get(Person_.age), "xyz") 将导致编译器错误,因为编译器通过 QueryBuilder.gt(..) 的签名和 Person_.age 的类型可以确定 Person 的 age 属性是一个数字字段,不能与 String 进行比较。

* 元模型类被注释为 @StaticMetamodel(domain.Person.class) 以将其标记为一个与原来的持久化 domain.Person 实体对应的元模型类。



[Criteria API]

* This dynamic query definition capability, referred as Criteria API, is based on the:
  • abstract persistent schema of the entities.
  • their embedded objects.
  • their relationships.

* The first step in constructing a query definition is specification of query roots.
  • Query roots
    • Specify the domain objects on which the query is evaluated. 
    • Is an instance of the Root interface. 
    • A query root is added to a CriteriaQuery by addRoot(Class c) method.

* A query domain can be further refined by joining to other domain objects.

* An attribute of a domain object can also be specified by navigating via get(String attr). The attribute should refer to a valid persistent property of the receiving domain object, however no such validation is enforced during the construction of the query definition.

CriteriaBuilder interface
  • The factory for CriteriaQuery. 
  • Is obtained from either an EntityManagerFactory or an EntityManager.

* queryBuilder
  • 是 CriteriaQuery 的工厂,同时也是查询表达式的工厂。
  • 包含构造传统 JPQL 语法支持的所有查询表达式的 API 方法,并且还包含额外的方法。

* CriteriaQuery
  • 一个查询表达式节点树。
  • 在传统的基于字符串的查询语言中,这些表达式节点用于指定查询子句,比如 FROM、WHERE 和 ORDER BY。


* Reference
- JPA 2.0 中的动态类型安全查询(3)
- JPA 2.0 中的动态类型安全查询(4)
- 详解JPA 2.0动态查询机制:Criteria API(1)
- 详解JPA 2.0动态查询机制:Criteria API(2)
- Part 2. Java Persistence API

沒有留言:

張貼留言