基于字符串的 Criteria 查询

本章介绍如何创建弱类型的基于字符串的 Criteria API 查询。

主要讨论以下主题:

  • 基于字符串的 Criteria API 查询的概述
  • 创建基于字符串的查询
  • 执行基于字符串的查询

概述

基于字符串的Criteria API查询(简称“基于字符串的查询”)是Java编程语言查询,它使用字符串而不是强类型元模型对象,以遍历数据层次结构时指定实体属性。 基于字符串的查询构造类似于元模型查询,可以是静态或动态的,并且可以表示与强类型化的元模型查询相同类型的查询和操作。

强类型的元模型查询是构造Criteria API 查询的首选方法。

基于字符串的查询对于元模型查询的主要优点是能够在开发时构造 Criteria 查询,而无需生成静态元模型类或以其他方式访问动态生成的元模型类。

基于字符串的查询的主要缺点是缺乏类型安全性。这个问题可能导致运行时错误,由于类型不匹配,如果你使用强类型的元模型查询,将在开发时捕获。

创建基于字符串的查询

要创建基于字符串的查询,请直接将实体类的属性名称指定为字符串,而不是指定元模型类的属性。例如,此查询查找名称属性的值为 Fido 的所有 Pet 实体:

  1. CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
  2. Root<Pet> pet = cq.from(Pet.class);
  3. cq.where(cb.equal(pet.get("name"), "Fido"));

属性的名称被指定为字符串。此查询等同于以下元模型查询:

  1. CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
  2. Metamodel m = em.getMetamodel();
  3. EntityType<Pet> Pet_ = m.entity(Pet.class);
  4. Root<Pet> pet = cq.from(Pet.class);
  5. cq.where(cb.equal(pet.get(Pet_.name), "Fido"));

注意:
基于字符串的查询中的类型不匹配错误将不会出现,直到代码在运行时执行,不像上面的元模型查询,其中类型不匹配将在编译时捕获。

连接操作以相同的方式指定:

  1. CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
  2. Root<Pet> pet = cq.from(Pet.class);
  3. Join<Owner, Address> address = pet.join("owners").join("addresses");

在元模型查询中使用的所有条件表达式、方法表达式、路径导航方法和结果限制方法也可以在基于字符串的查询中使用。在每种情况下,使用字符串指定属性。例如,以下是使用 in 表达式的基于字符串的查询:

  1. CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
  2. Root<Pet> pet = cq.from(Pet.class);
  3. cq.where(pet.get("color").in("brown", "black"));

这是一个基于字符串的查询,按日期按降序排列结果:

  1. CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
  2. Root<Pet> pet = cq.from(Pet.class);
  3. cq.select(pet);
  4. cq.orderBy(cb.desc(pet.get("birthday")));

执行基于字符串的查询

基于字符串的查询类似于强类型的 Criteria 查询执行。 首先,通过将条件查询对象传递到 EntityManager.createQuery 方法来创建 javax.persistence.TypedQuery 对象,然后在查询对象上调用 getSingleResult或getResultList 来执行查询:

  1. CriteriaQuery<Pet> cq = cb.createQuery(Pet.class);
  2. Root<Pet> pet = cq.from(Pet.class);
  3. cq.where(cb.equal(pet.get("name"), "Fido"));
  4. TypedQuery<Pet> q = em.createQuery(cq);
  5. List<Pet> results = q.getResultList();