Java 持久化/Criteria
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是进入 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定义了数据库 select 查询。一个CriteriaQuery对 JPQL select 查询的所有子句进行建模。来自一个CriteriaQuery的元素不能用于其他CriteriaQuerys。一个CriteriaQuery与EntityManager 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元素派生表达式。
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. From在 from 子句中定义了一个变量,并允许联接。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 子句中的集合关系以过滤将要获取的相关对象时才会成为问题。不应执行此操作,但有时是可取的,在这种情况下,查询应确保已将其设置为绕过缓存。
默认情况下join和fetch是内部联接。这意味着没有关系的结果将从查询结果中过滤掉。为了避免这种情况,可以使用 LEFT 将联接定义为外部联接JoinType作为join或fetch操作的参数。
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使用asc或descAPI。
// 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定义了数据库更新查询。一个CriteriaUpdate对 JPQL 更新查询的所有子句进行建模。来自一个CriteriaUpdate的元素不能用于其他CriteriaUpdates。一个CriteriaUpdate与EntityManager 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元素派生表达式。
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定义了数据库删除查询。一个CriteriaDelete对 JPQL 删除查询的所有子句进行建模。来自一个CriteriaDelete的元素不能用于其他CriteriaDelete。一个CriteriaDelete与EntityManager createQuery()API 一起使用以创建 JPAQuery. CriteriaDelete只能用于批处理删除。对于对象的定期删除,应通过事务中的 EntityManager
读取对象,并通过 remove()
API 删除对象,并提交更改。
CriteriaDelete定义了以下子句和选项
- where(Expression), where(Predicate...)- 定义删除的 where 子句。默认情况下,删除类的所有实例。
的Expressions, Predicates元素使用CriteriaBuilderAPI 定义,并从from Root元素派生表达式。
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
操作 | 描述 | 示例 |
---|---|---|
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")
|
操作 | 描述 | 示例 |
---|---|---|
和 | 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, any或some操作一起使用,或者与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.
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 标准,并且没有等效的函数。
函数 | 描述 | 示例 |
---|---|---|
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上定义的,而另一些则是在特定表达式接口上定义的。
函数 | 描述 | 示例 |
---|---|---|
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)
|
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");