JPA Criteria Queries – JPA标准查询

最后修改: 2022年 11月 11日

1. Overview

1.概述

In this tutorial, we’ll discuss a very useful JPA feature — Criteria Queries.

在本教程中,我们将讨论一个非常有用的JPA特性–标准查询。

It enables us to write queries without doing raw SQL as well as gives us some object-oriented control over the queries, which is one of the main features of Hibernate. The Criteria API allows us to build up a criteria query object programmatically, where we can apply different kinds of filtration rules and logical conditions.

它使我们能够在不做原始SQL的情况下编写查询,并使我们对查询有一些面向对象的控制,这也是Hibernate的主要特点之一。Criteria API允许我们以编程方式建立一个标准查询对象,在那里我们可以应用不同类型的过滤规则和逻辑条件。

Since Hibernate 5.2, the Hibernate Criteria API is deprecated, and new development is focused on the JPA Criteria API. We’ll explore how to use Hibernate and JPA to build Criteria Queries.

自Hibernate 5.2以来,Hibernate Criteria API已被废弃,新的开发重点是JPA Criteria API。我们将探讨如何使用Hibernate和JPA来构建标准查询。

2. Maven Dependencies

2.Maven的依赖性

To illustrate the API, we’ll use the reference JPA implementation Hibernate.

为了说明这个API,我们将使用参考JPA实现Hibernate。

To use Hibernate, we’ll make sure to add the latest version of it to our pom.xml file:

为了使用Hibernate,我们要确保在我们的pom.xml文件中添加最新版本的Hibernate。

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>   
    <version>5.3.2.Final</version>
</dependency>

We can find the latest version of Hibernate here.

我们可以在这里找到Hibernate的最新版本。

3. Simple Example Using Criteria

3.使用标准的简单例子

Let’s start by looking at how to retrieve data using Criteria Queries. We’ll look at how to get all the instances of a particular class from the database.

让我们先来看看如何使用标准查询来检索数据。我们将看看如何从数据库中获取一个特定类的所有实例。

We have an Item class that represents the tuple “ITEM” in the database:

我们有一个Item类,代表数据库中的元组“ITEM”

public class Item implements Serializable {

    private Integer itemId;
    private String itemName;
    private String itemDescription;
    private Integer itemPrice;

   // standard setters and getters
}

Let’s look at a simple criteria query that will retrieve all the rows of “ITEM” from the database:

让我们看看一个简单的标准查询,它将从数据库中检索所有“item”的行。

Session session = HibernateUtil.getHibernateSession();
CriteriaBuilder cb = session.getCriteriaBuilder();
CriteriaQuery<Item> cr = cb.createQuery(Item.class);
Root<Item> root = cr.from(Item.class);
cr.select(root);

Query<Item> query = session.createQuery(cr);
List<Item> results = query.getResultList();

The above query is a simple demonstration of how to get all the items. Let’s see it step by step:

上面的查询是一个简单的示范,说明如何获得所有的项目。让我们一步一步地看。

  1. Create an instance of Session from the SessionFactory object
  2. Create an instance of CriteriaBuilder by calling the getCriteriaBuilder() method
  3. Create an instance of CriteriaQuery by calling the CriteriaBuilder createQuery() method
  4. Create an instance of Query by calling the Session createQuery() method
  5. Call the getResultList() method of the query object, which gives us the results

Now that we’ve covered the basics, let’s move on to some of the features of criteria query.

现在我们已经涵盖了基础知识,让我们继续讨论标准查询的一些功能。

3.1. Using Expressions

3.1.使用表达式

The CriteriaBuilder can be used to restrict query results based on specific conditions, by using CriteriaQuery where() method and providing Expressions created by CriteriaBuilder.

通过使用CriteriaQuery where()方法和提供由CriteriaBuilder创建的Expressions,可以根据特定条件限制查询结果

Let’s see some examples of commonly used Expressions.

让我们看看一些常用的表达式的例子。

In order to get items having a price of more than 1000:

为了获得价格超过1000的物品。

cr.select(root).where(cb.gt(root.get("itemPrice"), 1000));

Next, getting items having itemPrice less than 1000:

接下来,获得itemPrice小于1000的项目。

cr.select(root).where(cb.lt(root.get("itemPrice"), 1000));

Items having itemName contain Chair:

具有itemName的项目包含Chair

cr.select(root).where(cb.like(root.get("itemName"), "%chair%"));

Records having itemPrice between 100 and 200:

itemPrice在100和200之间的记录。

cr.select(root).where(cb.between(root.get("itemPrice"), 100, 200));

Items having itemName in Skate Board, Paint and Glue:

项目的itemName滑板油漆胶水

cr.select(root).where(root.get("itemName").in("Skate Board", "Paint", "Glue"));

To check if the given property is null:

检查给定属性是否为空。

cr.select(root).where(cb.isNull(root.get("itemDescription")));

To check if the given property is not null:

检查给定的属性是否为空。

cr.select(root).where(cb.isNotNull(root.get("itemDescription")));

We can also use the methods isEmpty() and isNotEmpty() to test if a List within a class is empty or not.

我们还可以使用isEmpty()isNotEmpty()方法来测试一个类中的List是否为空。

Additionally, we can combine two or more of the above comparisons. The Criteria API allows us to easily chain expressions:

此外,我们可以将上述两个或多个比较结合起来。TCriteria API允许我们轻松地连锁表达式

Predicate[] predicates = new Predicate[2];
predicates[0] = cb.isNull(root.get("itemDescription"));
predicates[1] = cb.like(root.get("itemName"), "chair%");
cr.select(root).where(predicates);

To add two expressions with logical operations:

要用逻辑运算添加两个表达式。

Predicate greaterThanPrice = cb.gt(root.get("itemPrice"), 1000);
Predicate chairItems = cb.like(root.get("itemName"), "Chair%");

Items with the above-defined conditions joined with Logical OR:

具有上述定义条件的项目用逻辑OR连接。

cr.select(root).where(cb.or(greaterThanPrice, chairItems));

To get items matching with the above-defined conditions joined with Logical AND:

要获得与上述定义的条件相匹配的项目,并加入逻辑和

cr.select(root).where(cb.and(greaterThanPrice, chairItems));

3.2. Sorting

3.2.分拣

Now that we know the basic usage of Criteria, let’s look at the sorting functionalities of Criteria.

现在我们知道了Criteria的基本用法,让我们看看Criteria的排序功能。

In the following example, we order the list in ascending order of the name and then in descending order of the price:

在下面的例子中,我们按名字的升序排列,然后按价格的降序排列。

cr.orderBy(
  cb.asc(root.get("itemName")), 
  cb.desc(root.get("itemPrice")));

In the next section, we will have a look at how to do aggregate functions.

在下一节中,我们将看一下如何做聚合函数。

3.3. Projections, Aggregates and Grouping Functions

3.3.投影、聚合和分组函数

Now let’s see the different aggregate functions.

现在我们来看看不同的聚合函数。

Get row count:

获得行数。

CriteriaQuery<Long> cr = cb.createQuery(Long.class);
Root<Item> root = cr.from(Item.class);
cr.select(cb.count(root));
Query<Long> query = session.createQuery(cr);
List<Long> itemProjected = query.getResultList();

The following is an example of aggregate functions — Aggregate function for Average:

下面是一个集合函数的例子 – Aggregate函数为Average

CriteriaQuery<Double> cr = cb.createQuery(Double.class);
Root<Item> root = cr.from(Item.class);
cr.select(cb.avg(root.get("itemPrice")));
Query<Double> query = session.createQuery(cr);
List avgItemPriceList = query.getResultList();

Other useful aggregate methods are sum(), max(), min(), count(), etc.

其他有用的聚合方法有sum()max()min(),count()等。

3.4. CriteriaUpdate

3.4.CriteriaUpdate

Starting from JPA 2.1, there’s support for performing database updates using the Criteria API.

从JPA 2.1开始,支持使用Criteria API执行数据库更新。

CriteriaUpdate has a set() method that can be used to provide new values for database records:

CriteriaUpdate有一个set()方法,可用于为数据库记录提供新值。

CriteriaUpdate<Item> criteriaUpdate = cb.createCriteriaUpdate(Item.class);
Root<Item> root = criteriaUpdate.from(Item.class);
criteriaUpdate.set("itemPrice", newPrice);
criteriaUpdate.where(cb.equal(root.get("itemPrice"), oldPrice));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaUpdate).executeUpdate();
transaction.commit();

In the above snippet, we create an instance of CriteriaUpdate<Item> from the CriteriaBuilder and use its set() method to provide new values for the itemPrice. In order to update multiple properties, we just need to call the set() method multiple times.

在上面的片段中,我们从CriteriaBuilder创建了CriteriaUpdate<Item>的实例,并使用其set()方法来为itemPrice提供新的值。为了更新多个属性,我们只需要多次调用set()方法。

3.5. CriteriaDelete

3.5.CriteriaDelete

CriteriaDelete enables a delete operation using the Criteria API.

CriteriaDelete可使用Criteria API进行删除操作。

We just need to create an instance of CriteriaDelete and use the where() method to apply restrictions:

我们只需要创建一个CriteriaDelete的实例,并使用where()方法来应用限制。

CriteriaDelete<Item> criteriaDelete = cb.createCriteriaDelete(Item.class);
Root<Item> root = criteriaDelete.from(Item.class);
criteriaDelete.where(cb.greaterThan(root.get("itemPrice"), targetPrice));

Transaction transaction = session.beginTransaction();
session.createQuery(criteriaDelete).executeUpdate();
transaction.commit();

4. Advantage Over HQL

4.相对于HQL的优势

In the previous sections, we covered how to use Criteria Queries.

在前面的章节中,我们介绍了如何使用标准查询。

Clearly, the main and most hard-hitting advantage of Criteria Queries over HQL is the nice, clean, object-oriented API.

显然,相对于HQL而言,标准查询的主要和最有力的优势是漂亮、干净、面向对象的API。

We can simply write more flexible, dynamic queries compared to plain HQL. The logic can be refactored with the IDE and has all the type-safety benefits of the Java language itself.

与普通的HQL相比,我们可以简单地编写更灵活、更动态的查询。这些逻辑可以通过IDE进行重构,并且具有Java语言本身的所有类型安全优势。

Of course, there are some disadvantages as well, especially around more complex joins.

当然,也有一些缺点,特别是在更复杂的连接周围。

So, we generally have to use the best tool for the job — that can be the Criteria API in most cases, but there are definitely cases where we’ll have to go lower level.

因此,我们通常必须使用最好的工具来完成工作–在大多数情况下,这可能是Criteria API,但肯定有一些情况下,我们必须使用更低级别的工具。

5. Conclusion

5.结论

In this article, we focused on the basics of Criteria Queries in Hibernate and JPA as well as on some of the advanced features of the API.

在这篇文章中,我们着重介绍了Hibernate和JPA中的标准查询的基础知识,以及API的一些高级功能。

The code discussed here is available in the GitHub repository.

这里讨论的代码可在GitHub 仓库中找到。