跳转到内容

Java 持久化/Criteria

来自 Wikibooks,开放的书籍,开放的世界

Criteria API

[编辑 | 编辑源代码]

Java 持久化 Criteria API 用于通过构建基于对象的查询定义对象来定义动态查询,而不是使用 JPQL 的基于字符串的方法。Criteria API 允许以编程方式构建动态查询,与基于字符串的第 4 代语言相比,它提供了更好的 Java 语言集成。

Criteria API 有两种模式,类型限制模式和非类型模式。类型限制模式使用一组 JPA 元模型生成的类来定义类的可查询属性,请参见元模型。非类型模式使用字符串引用类的属性。

Criteria API 仅用于动态查询,不能用于元数据或命名查询。Criteria 查询是动态查询,因此不如静态命名查询或甚至动态参数化 JPQL(在某些 JPA 提供程序中可能受益于解析缓存)那样高效。

Criteria API 添加于 JPA 2.0 中。

Criteria API 删除和更新支持添加于 JPA 2.1 中。

CriteriaBuilder

[编辑 | 编辑源代码]

CriteriaBuilder是进入 Criteria API 的主要接口。一个CriteriaBuilder从一个EntityManager或一个EntityManagerFactory使用getCriteriaBuilder()API。CriteriaBuilder用于构造CriteriaQuery对象及其表达式。Criteria API 目前仅支持 select 查询。

CriteriaBuilder定义了用于创建CriteriaQuery对象的 API

  • createQuery()- 创建一个CriteriaQuery.
  • createQuery(Class)- 创建一个CriteriaQuery使用泛型来避免强制转换结果类。
  • createTupleQuery()- 创建一个CriteriaQuery返回类似于 map 的Tuple对象,而不是用于多选查询的对象数组。请参见Tuple Queries
  • createCriteriaDelete(Class)- 创建一个CriteriaDelete直接在数据库上删除一批对象(JPA 2.1)。
  • createCriteriaUpdate(Class)- 创建一个CriteriaUpdate直接在数据库上更新一批对象(JPA 2.1)。

CriteriaBuilder还定义了所有支持的比较运算和函数,这些运算和函数用于定义查询的子句。

CriteriaQuery

[编辑 | 编辑源代码]

CriteriaQuery定义了数据库 select 查询。一个CriteriaQuery对 JPQL select 查询的所有子句进行建模。来自一个CriteriaQuery的元素不能用于其他CriteriaQuerys。一个CriteriaQueryEntityManager createQuery()API 一起使用以创建 JPAQuery.

CriteriaQuery定义了以下子句和选项

  • distinct(boolean)- 定义查询是否应该过滤重复结果(默认为 false)。如果使用与集合关系的连接,则应使用 distinct 以避免重复结果。
  • from(Class)- 为实体类定义并返回查询的 from 子句中的一个元素。查询至少需要一个 from 元素才能有效。
  • from(EntityType)- 为元模型实体类型定义并返回查询的 from 子句中的一个元素。查询至少需要一个 from 元素才能有效。
  • select(Selection)- 定义查询的 select 子句。如果未设置,则默认情况下将选择第一个根。
  • multiselect(Selection...), multiselect(List<Selection>)- 定义多选查询。
  • where(Expression), where(Predicate...)- 定义查询的 where 子句。默认情况下,将选择该类所有实例。
  • orderBy(Order...), orderBy(List<Order>)- 定义查询的 order 子句。默认情况下,结果未排序。
  • groupBy(Expression...), groupBy(List<Expression>)- 定义查询的 group by 子句。默认情况下,结果未分组。
  • having(Expression), having(Predicate...)- 定义查询的 having 子句。Having 允许对分组结果进行过滤。
  • subQuery(Class)- 创建一个subQuery用于其他子句之一。

Expressions, Predicates, Order元素使用CriteriaBuilderAPI 定义,并从from Root元素派生表达式。

CriteriaQuery 示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Query for a List of objects.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(criteriaBuilder.greaterThan(employee.get("salary"), 100000));
Query query = entityManager.createQuery(criteriaQuery);
List<Employee> result = query.getResultList();

// Query for a single object.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(criteriaBuilder.equal(employee.get("id"), criteriaBuilder.parameter(Long.class, "id")));
Query query = entityManager.createQuery(criteriaQuery);
query.setParameter("id", id);
Employee result2 = (Employee)query.getSingleResult();

// Query for a single data element.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.max(employee.get("salary")));
Query query = entityManager.createQuery(criteriaQuery);
BigDecimal result3 = (BigDecimal)query.getSingleResult();

// Query for a List of data elements.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(employee.get("firstName"));
Query query = entityManager.createQuery(criteriaQuery);
List<String> result4 = query.getResultList();

// Query for a List of element arrays.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.multiselect(employee.get("firstName"), employee.get("lastName"));
Query query = entityManager.createQuery(criteriaQuery);
List<Object[]> result5 = query.getResultList();

一个选择定义了查询选择的内容。一个选择可以是任何对象表达式、属性表达式、函数、子选择、构造函数或聚合函数。一个别名可以为一个选择使用alias()API。

聚合函数

[编辑 | 编辑源代码]

聚合函数可以包含有关一组对象的汇总信息。这些函数可以用来返回单个结果,也可以与groupBy一起使用来返回多个结果。

聚合函数定义在CriteriaBuilder上,并包括

  • max(Expression)- 返回所有结果的最大值。用于数值类型。
  • greatest(Expression)- 返回所有结果的最大值。用于非数值类型。
  • min(Expression)- 返回所有结果的最小值。用于数值类型。
  • least(Expression)- 返回所有结果的最小值。用于非数值类型。
  • avg(Expression)- 返回所有结果的平均值。一个Double被返回。
  • sum(Expression)- 返回所有结果的总和。
  • sumAsLong(Expression)- 返回所有结果的总和。一个Long被返回。
  • sumAsDouble(Expression)- 返回所有结果的总和。一个Double被返回。
  • count(Expression)- 返回所有结果的计数。null值不计入计数。一个Long被返回。
  • countDistinct(Expression)- 返回所有不同结果的计数。null值不计入计数。一个Long被返回。
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Count the total employees
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.count(employee));
Query query = entityManager.createQuery(criteriaQuery);
Long result = query.getSingleResult();

// Maximum salary
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.max(employee.get("salary"));
Query query = entityManager.createQuery(criteriaQuery);
Long result = query.getSingleResult();

构造函数

[编辑 | 编辑源代码]

construct运算符在CriteriaBuilder上可以使用类和值从 Criteria 查询返回数据对象。这些将不是托管对象,并且该类必须定义一个与参数和类型匹配的构造函数。构造函数查询可用于选择对象上的部分数据或报告数据,并返回类实例而不是对象数组或元组。

CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.select(criteriaBuilder.construct(EmpReport.class, employee.get("firstName"), employee.get("lastName"), employee.get("salary")));
Query query = entityManager.createQuery(criteriaQuery);
List<EmpReport> result = query.getResultList();

查询的 from 子句定义了要查询的内容。from 子句使用fromAPI onCriteriaQuery。一个Root对象从from返回,代表查询上下文中的对象。一个Root也实现了From,并且Path. Fromfrom 子句中定义了一个变量,并允许联接。Path定义了任何属性值,并允许遍历嵌套属性。

Root employee = criteriaQuery.from(Employee.class);

Criteria 查询允许多个根级对象。在执行此操作时应谨慎,因为它会导致两个表的笛卡尔积。where 子句应确保两个对象以某种方式联接。

// Select the employees and the mailing addresses that have the same address.
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Root address = criteriaQuery.from(MailingAddress.class);
criteriaQuery.multiselect(employee, address);
criteriaQuery.where(criteriaBuilder.equal(employee.get("address"), address.get("address"));
Query query = entityManager.createQuery(criteriaQuery);
List<Object[]> result = query.getResultList();

一个join操作可用于From对象以获取要用于查询的关系。join并不意味着将获取关系,要获取结果中相关对象,请使用fetch操作。

Root employee = criteriaQuery.from(Employee.class);
Join address = employee.join("address");
criteriaQuery.where(criteriaBuilder.equal(address.get("city"), city);

join操作可用于 OneToOne、ManyToOne、OneToMany、ManyToMany 和 ElementCollection 映射。当与集合关系一起使用时,可以多次联接相同的关系以查询多个独立的值。

// All employees who work on both projects.
Root employee = criteriaQuery.from(Employee.class);
Join p = employee.join("projects");
Join p2 = employee.join("projects");
criteriaQuery.where(criteriaBuilder.and(criteriaBuilder.equal(p.get("name"), projectName1), criteriaBuilder.equal(p2.get("name"), projectName2));

fetch操作可用于From对象以在单个查询中获取相关对象。这避免了对每个对象的每个关系的额外查询,并确保如果关系为 LAZY,则已获取关系。

Root employee = criteriaQuery.from(Employee.class);
Fetch address = employee.fetch("address");
criteriaQuery.select(employee);

在使用获取where 子句中应谨慎,因为它会影响结果对象关系的返回数据。对象通常应始终具有相同的数据,无论它们如何被查询,这对缓存和一致性很重要。这只有在别名用于 where 子句中的集合关系以过滤将要获取的相关对象时才会成为问题。不应执行此操作,但有时是可取的,在这种情况下,查询应确保已将其设置为绕过缓存。

默认情况下joinfetch是内部联接。这意味着没有关系的结果将从查询结果中过滤掉。为了避免这种情况,可以使用 LEFT 将联接定义为外部联接JoinType作为joinfetch操作的参数。

Root employee = criteriaQuery.from(Employee.class);
Join address = employee.join("address", JoinType.LEFT);
criteriaQuery.order(address.get("city"));

查询的 order by 子句定义了查询结果的排序方式。order by 子句使用orderByAPI onCriteriaQuery定义。只有Order对象可以传递给orderBy,并且从CriteriaBuilder使用ascdescAPI。

// Order by the last and first names.
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.orderBy(criteriaBuilder.desc(employee.get("lastName")), criteriaBuilder.asc(employee.get("firstName")));
// Order by the last name, ignoring case.
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.orderBy(criteriaBuilder.asc(criteriaBuilder.upper(employee.get("lastName"))));
// Order by the address object (orders by its id).
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.orderBy(criteriaBuilder.asc(employee.get("address")));

分组依据

[编辑 | 编辑源代码]

查询的 group by 子句允许对一组对象计算汇总信息。group by 通常与聚合函数一起使用。group by 子句使用groupByAPI onCriteriaQuery定义,其中包含任何有效的Expression对象。

// Select the average salaries grouped by city.
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.multiselect(criteriaBuilder.avg(employee.<Number>get("salary")), employee.get("address").get("city"));
criteriaQuery.groupBy(employee.get("address").get("city"));
// Select the average salaries grouped by city, ordered by the average salary.
Root employee = criteriaQuery.from(Employee.class);
Expression avg = criteriaBuilder.avg(employee.<Number>get("salary"));
criteriaQuery.multiselect(avg, employee.get("address").get("city"));
criteriaQuery.groupBy(employee.get("address").get("city"));
criteriaQuery.orderBy(criteriaBuilder.asc(avg));
// Select employees and the count of their number of projects.
Root employee = criteriaQuery.from(Employee.class);
Expression project = employee.join("projects", JoinType.LEFT);
criteriaQuery.multiselect(e, criteriaBuilder.count(project));
criteriaQuery.groupBy(employee);

查询的 having 子句允许过滤 group by 的结果。having 子句使用havingAPI onCriteriaQuery定义,其中包含任何Predicate对象。

// Select the average salaries grouped by city, only including cities with average salaries over 100000.
Root employee = criteriaQuery.from(Employee.class);
Expression avg = criteriaBuilder.avg(employee.<Number>get("salary"));
criteriaQuery.multiselect(avg, employee.get("address").get("city"));
criteriaQuery.groupBy(employee.get("address").get("city"));
criteriaQuery.having(criteriaBuilder.greaterThan(avg, 100000));

CriteriaUpdate (JPA 2.1)

[编辑 | 编辑源代码]

CriteriaUpdate定义了数据库更新查询。一个CriteriaUpdate对 JPQL 更新查询的所有子句进行建模。来自一个CriteriaUpdate的元素不能用于其他CriteriaUpdates。一个CriteriaUpdateEntityManager createQuery()API 一起使用以创建 JPAQuery。Criteria 更新只能用于批处理更新。对于对对象的定期更新,应通过事务中的 EntityManager 读取对象,并在 Java 中修改对象,并提交更改。

CriteriaUpdate定义了以下子句和选项

  • set(String, Object), set(Path, Object), set(Path, Expression)- 定义更新的 set 子句。
  • where(Expression), where(Predicate...)- 定义更新的 where 子句。默认情况下,更新类的所有实例。

Expressions, Predicates元素使用CriteriaBuilderAPI 定义,并从from Root元素派生表达式。

CriteriaUpdate 示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Updates the salary to 90,000 of all Employee's making more than 100,000.
CriteriaUpdate update = criteriaBuilder.createCriteriaUpdate(Employee.class);
Root employee = update.from(Employee.class);
update.set("salary", 90000);
update.where(criteriaBuilder.greaterThan(employee.get("salary"), 100000));
Query query = entityManager.createQuery(update);
int rowCount = query.executeUpdate();

// Gives all Employees a 10% raise.
CriteriaUpdate update = criteriaBuilder.createCriteriaUpdate(Employee.class);
Root employee = update.from(Employee.class);
update.set(employee.get("salary"), criteriaBuilder.sum(employee.get("salary"), criteriaBuilder.quot(employee.get("salary"), 10));
Query query = entityManager.createQuery(update);
int rowCount = query.executeUpdate();

CriteriaDelete (JPA 2.1)

[编辑 | 编辑源代码]

CriteriaDelete定义了数据库删除查询。一个CriteriaDelete对 JPQL 删除查询的所有子句进行建模。来自一个CriteriaDelete的元素不能用于其他CriteriaDelete。一个CriteriaDeleteEntityManager createQuery()API 一起使用以创建 JPAQuery. CriteriaDelete只能用于批处理删除。对于对象的定期删除,应通过事务中的 EntityManager 读取对象,并通过 remove() API 删除对象,并提交更改。

CriteriaDelete定义了以下子句和选项

  • where(Expression), where(Predicate...)- 定义删除的 where 子句。默认情况下,删除类的所有实例。

Expressions, Predicates元素使用CriteriaBuilderAPI 定义,并从from Root元素派生表达式。

CriteriaDelete 示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Deletes all Employee's making more than 100,000.
CriteriaDelete delete = criteriaBuilder.createCriteriaDelete(Employee.class);
Root employee = delete.from(Employee.class);
delete.where(criteriaBuilder.greaterThan(employee.get("salary"), 100000));
Query query = entityManager.createQuery(delete);
int rowCount = query.executeUpdate();

// Deletes all Employees.
CriteriaDelete delete = criteriaBuilder.createCriteriaDelete(Employee.class);
Root employee = delete.from(Employee.class);
Query query = entityManager.createQuery(delete);
int rowCount = query.executeUpdate();

where 子句通常是查询的主要部分,因为它定义了过滤返回内容的条件(谓词)。where 子句使用whereAPI onCriteriaQuery定义,其中包含任何Predicate对象定义。一个Predicate使用比较运算符或对CriteriaBuilder的逻辑运算符获得。该isNull, isNotNull,并且in操作也可以在Expression的逻辑运算符获得。该not操作也可以在Predicate

上定义的比较运算符CriteriaBuilder

[编辑 | 编辑源代码]
操作 描述 示例
equal, notEqual equal
criteriaBuilder.equal(employee.get("firstName"), "Bob")
lessThan, lt 小于
criteriaBuilder.lessThan(employee.get("salary"), 100000)
greaterThan, gt 大于
criteriaBuilder.greaterThan(employee.get("salary"), criteriaBuilder.parameter(Integer.class, "sal"))
lessThanOrEqualTo, le 小于或等于
criteriaBuilder.lessThanOrEqualTo(employee.get("salary"), 100000)
greaterThanOrEqualTo, ge 大于或等于
criteriaBuilder.greaterThanOrEqualTo(employee.get("salary"), criteriaBuilder.parameter(Integer.class, "sal"))
like, notLike 评估两个字符串是否匹配,'%' 和 '_' 是有效的通配符,并且 ESCAPE 字符是可选的
criteriaBuilder.like(employee.get("firstName"), "A%")
criteriaBuilder.notLike(employee.get("firstName"), "%._%", '.')
between 评估值是否在两个值之间
criteriaBuilder.between(employee.<String>get("firstName"), "A", "C")
isNull 将值与 null 进行比较,数据库可能不允许或在将 = 与 null 一起使用时产生意外结果
criteriaBuilder.isNull(employee.get("endDate"))
employee.get("endDate").isNull()
in 评估值是否包含在列表中
criteriaBuilder.in(employee.get("firstName")).value("Bob").value("Fred").value("Joe")
employee.get("firstName").in("Bob", "Fred", "Joe")
employee.get("firstName").in(criteriaBuilder.parameter(List.class, "names")

CriteriaBuilder 上定义的逻辑运算符CriteriaBuilder

[编辑 | 编辑源代码]
操作 描述 示例
and 将两个或多个谓词组合在一起
criteriaBuilder.and(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("lastName"), "Smith"))
or 将两个或多个谓词组合在一起
criteriaBuilder.or(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("firstName"), "Bobby"))
not 否定谓词
criteriaBuilder.not(criteriaBuilder.or(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("firstName"), "Bobby")))
criteriaBuilder.or(criteriaBuilder.equal(employee.get("firstName"), "Bob"), criteriaBuilder.equal(employee.get("firstName"), "Bobby")).not()
连接 表示 true 的谓词
Predicate where = criteriaBuilder.conjunction();
if (name != null) {
    where = criteriaBuilder.and(where, criteriaBuilder.equal(employee.get("firstName"), name));
}
析取 表示 false 的谓词
Predicate where = criteriaBuilder.disjunction();
if (name != null) {
    where = criteriaBuilder.or(where, criteriaBuilder.equal(employee.get("firstName"), name));
}

子查询

[编辑 | 编辑源代码]

子查询只能在 where 子句和 having 子句中使用。子查询从CriteriaQuery使用subQuery操作创建。大多数子查询用法将子查询限制为返回单个结果和值,除非与CriteriaBuilder exists, all, anysome操作一起使用,或者与in操作的参数。

子查询示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();

// Find all manager that only manage below-average employees.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Subquery subQuery = criteriaQuery.subquery(Employee.class);
Root employee_2 = subQuery.from(Employee.class);
subQuery.where(criteriaBuilder.and(employee_2.get("manager").equal(e), criteriaBuilder.equal(employee_2.get("productivity"), "below average").not());
criteriaQuery.where(criteriaBuilder.exists(subQuery).not());
Query query = entityManager.createQuery(criteriaQuery)
List<Employee> = query.getResultList();

// Find the employee with the lowest salary.
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
Subquery subQuery = criteriaQuery.subquery(Employee.class);
Root employee_2 = subQuery.from(Employee.class);
subQuery.select(employee_2.get("salary"));
criteriaQuery.where(criteriaBuilder.lessThan(employee.get("salary"), criteriaBuilder.all(subQuery)));
Query query = entityManager.createQuery(criteriaQuery)
List<Employee> = query.getResultList();

可以使用parameterAPI onCriteriaBuilder定义参数。JPA 定义了命名参数和位置参数。对于命名参数,指定参数类型和名称。对于位置参数,只指定参数类型。位置参数从位置1not0.

命名参数 criteria 示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(
        criteriaBuilder.equal(employee.get("firstName"), criteriaBuilder.parameter(String.class, "first")),
        criteriaBuilder.equal(employee.get("lastName"), criteriaBuilder.parameter(String.class, "last"))
    );
Query query = entityManager.createQuery(criteriaQuery)
query.setParameter("first", "Bob");
query.setParameter("last", "Smith");
List<Employee> = query.getResultList();
位置参数标准示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.where(criteriaBuilder.equal(employee.get("firstName"), criteriaBuilder.parameter(String.class)), criteriaBuilder.equal(employee.get("lastName"), criteriaBuilder.parameter(String.class)));
Query query = entityManager.createQuery(criteriaQuery)
query.setParameter(1, "Bob");
query.setParameter(2, "Smith");
List<Employee> = query.getResultList();

Criteria API 支持一些数据库函数。所有支持的函数都在CriteriaBuilder上定义。一些函数可能不受某些数据库支持,因为它们不符合 SQL 标准,并且没有等效的函数。

CriteriaBuilder数据库函数

[编辑 | 编辑源代码]
函数 描述 示例
diff 减法
criteriaBuilder.diff(employee.<Number>get("salary"), 1000)
sum 加法
criteriaBuilder.sum(employee.<Number>get("salary"), 1000)
prod 乘法
criteriaBuilder.prod(employee.<Number>get("salary"), 2)
quot 除法
criteriaBuilder.quot(employee.<Number>get("salary"), 2)
abs 绝对值
criteriaBuilder.abs(
    criteriaBuilder.diff(employee.<Number>get("salary"), employee.get("manager").<Number>get("salary")))
selectCase 定义一个 case 语句
criteriaBuilder.selectCase(employee.get("status")).
    when(0, "active").
    when(1, "consultant").
    otherwise("unknown")
criteriaBuilder.selectCase().
    when(criteriaBuilder.equal(employee.get("status"), 0), "active").
    when(criteriaBuilder.equal(employee.get("status"), 1), "consultant").
    otherwise("unknown")
coalesce 计算第一个非空参数的值
criteriaBuilder.coalesce(criteriaBuilder.concat(employee.<Number>get("salary"), 0)
concat 连接两个或多个字符串值
criteriaBuilder.concat(
    criteriaBuilder.concat(employee.<String>get("firstName"), " "), employee.<String>get("lastName"))
currentDate 数据库中的当前日期
criteriaBuilder.currentDate()
currentTime 数据库中的当前时间
criteriaBuilder.currentTime()
currentTimestamp 数据库中的当前日期时间
criteriaBuilder.currentTimestamp()
length 字符或二进制值的字符/字节长度
criteriaBuilder.length(employee.<String>get("lastName"))
locate 字符串在字符串中的索引,可以选择从起始索引开始
criteriaBuilder.locate("-", employee.<String>get("lastName"))
lower 将字符串值转换为小写
criteriaBuilder.lower(employee.<String>get("lastName"))
mod 计算第一个整数除以第二个整数的余数
criteriaBuilder.mod(employee.<Integer>get("hoursWorked"), 8)
nullif 如果第一个参数等于第二个参数,则返回 null,否则返回第一个参数
criteriaBuilder.nullif(employee.<Number>get("salary"), 0)
sqrt 计算数字的平方根
criteriaBuilder.sqrt(employee.<Number>get("salary"))
substring 字符串的子字符串,从索引开始,可以选择子字符串的大小
criteriaBuilder.substring(employee.<String>get("lastName"), 0, 2)
trim 从字符串中修剪开头、结尾或两端的空格或可选的修剪字符
criteriaBuilder.trim(TrimSpec.TRAILING, employee.<String>get("lastName"))
criteriaBuilder.trim(employee.<String>get("lastName"))
criteriaBuilder.trim(TrimSpec.LEADING, '-', employee.<String>get("lastName"))
upper 将字符串值转换为大写
criteriaBuilder.upper(employee.<String>get("lastName"))

特殊操作

[编辑 | 编辑源代码]

Criteria API 定义了一些特殊操作,这些操作不是数据库函数,但在 JPA 中具有特殊含义。其中一些操作是在CriteriaBuilder上定义的,而另一些则是在特定表达式接口上定义的。

Criteria API 特殊函数

[编辑 | 编辑源代码]
函数 描述 示例
index 排序列表元素的索引,仅在映射中使用 @OrderColumn 时支持,

ListJoin接口上定义,该接口从From元素使用joinList操作获得

Root employee = criteriaQuery.from(Employee.class);
ListJoin toDo = employee.joinList("toDoList");
criteriaQuery.multiselect(e, toDo);
criteriaQuery.where(criteriaBuilder.equal(toDo.index(), 1));
key, value 映射元素的键或值,在MapJoin接口上定义,该接口从From元素使用joinMap操作获得
Root employee = criteriaQuery.from(Employee.class);
MapJoin p = employee.joinMap("priorities");
criteriaQuery.multiselect(e, p.value());
criteriaQuery.where(criteriaBuilder.equal(p.key(), "high"))
size 集合关系的大小,这将计算为子查询,在CriteriaBuilder
criteriaBuilder.greaterThan(criteriaBuilder.size(employee.<Collection>get("managedEmployees")), 2)
isEmpty, isNotEmpty 上定义,它计算为真,如果集合关系为空或不为空,这将计算为子查询,在CriteriaBuilder
criteriaBuilder.isEmpty(employee.<Collection>get("managedEmployees"))
isMember, isNotMember 上定义,它计算为真,如果集合关系包含该值,这将计算为子查询,在CriteriaBuilder
criteriaBuilder.isMember("write code", employee.<Collection>get("responsibilities"))
type 继承鉴别器值,在任何Path表达式
criteriaBuilder.equal(p.type(), LargeProject.class)
as 可用于将非类型化表达式转换为类型化表达式,EclipseLink 还允许将继承类型向下转换
criteriaBuilder.mod(employee.get("id").as(Integer.class), 2)
criteriaBuilder.greaterThan(p.as(LargeProject.class).get("budget"), 1000000)
function 调用数据库特定函数,在CriteriaBuilder
criteriaBuilder.greaterThan(criteriaBuilder.function("TO_NUMBER", Number.class, p.get("areaCode")), 613)

Metamodel

[编辑 | 编辑源代码]

JPA 定义了一个元模型,它可以在运行时用于查询有关 ORM 映射元数据的的信息。元模型包括类映射属性的列表,以及它们的映射类型和基数。元模型可与 Criteria API 一起使用,以替代使用字符串引用类属性。

JPA 定义了一组_类,这些类将由 JPA 提供程序或 IDE 生成,从而在编译时访问元模型。这允许在 Criteria API 中使用类型化的静态变量。这可以通过在编译时而不是在测试期间捕获查询问题,来减少应用程序代码中出现拼写错误或无效查询的可能性。但是,它确实增加了开发过程的复杂性,因为元模型静态类需要生成并成为开发周期的一部分。

元模型标准示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
Root<Employee> employee = criteriaQuery.from(entityManager.getMetamodel().entity(Employee.class));
criteriaQuery.where(criteriaBuilder.equal(employee.get(Employee_.firstName), "Bob"), criteriaBuilder.equal(employee.get(Employee_.lastName), "Smith"));
Query query = entityManager.createQuery(criteriaQuery)
List<Employee> = query.getResultList();

元组查询

[编辑 | 编辑源代码]

一个Tuple定义一个多选查询结果。通常,JPA 多选查询会返回一个对象数组,但对象数组不是一个非常有用的数据结构。一个Tuple是一个类似于映射的结构,它允许通过名称或索引检索结果。

元组查询示例
[编辑 | 编辑源代码]
CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
CriteriaQuery<Tuple> criteriaQuery = criteriaBuilder.createTupleQuery();
Root employee = criteriaQuery.from(Employee.class);
criteriaQuery.multiselect(employee.get("firstName").alias("first"), employee.get("lastName").alias("last"));
Query query = entityManager.createQuery(criteriaQuery);
List<Tuple> results = query.getResultList();
String first = results.get(0).get("first");
String last = results.get(0).get("last");
华夏公益教科书