Kueri Kriteria JPA

1. Ikhtisar

Dalam tutorial ini, kita akan membahas fitur JPA yang sangat berguna - Query Kriteria.

Ini tidak hanya memungkinkan kita untuk menulis kueri tanpa melakukan SQL mentah, tetapi juga memberi kita beberapa kontrol Berorientasi Objek atas kueri, yang merupakan salah satu fitur utama Hibernate. API Kriteria memungkinkan kita membuat objek kueri kriteria secara terprogram, di mana kita dapat menerapkan berbagai jenis aturan penyaringan dan kondisi logis.

Sejak Hibernate 5.2, API Kriteria Hibernasi tidak digunakan lagi dan pengembangan baru difokuskan pada API Kriteria JPA. Kami akan mempelajari cara menggunakan Hibernate dan JPA untuk membuat Query Kriteria.

2. Ketergantungan Maven

Untuk menggambarkan API, kami akan menggunakan referensi implementasi JPA - Hibernate.

Untuk menggunakan Hibernate pastikan Anda menambahkan versi terbarunya ke file pom.xml Anda :

 org.hibernate hibernate-core 5.3.2.Final 

Versi terbaru Hibernate dapat ditemukan di sini.

3. Contoh Sederhana Menggunakan Kriteria

Mari kita mulai dengan melihat cara mengambil data menggunakan kueri Kriteria. Kita akan melihat bagaimana mendapatkan semua instance dari kelas tertentu dari database.

Kami memiliki kelas Item yang mewakili tupel "ITEM" dalam database:

public class Item implements Serializable { private Integer itemId; private String itemName; private String itemDescription; private Integer itemPrice; // standard setters and getters }

Mari kita lihat kueri kriteria sederhana yang akan mengambil semua baris " ITEM" dari database:

Session session = HibernateUtil.getHibernateSession(); CriteriaBuilder cb = session.getCriteriaBuilder(); CriteriaQuery cr = cb.createQuery(Item.class); Root root = cr.from(Item.class); cr.select(root); Query query = session.createQuery(cr); List results = query.getResultList();

Kueri di atas adalah demonstrasi sederhana tentang cara mendapatkan semua item. Mari kita lihat apa yang telah dilakukan, selangkah demi selangkah:

  1. Buat instance Session dari objek SessionFactory
  2. Membuat sebuah instance dari C riteriaBuilder dengan memanggil () getCriteriaBuilder metode
  3. Buat instance dari CriteriaQuery dengan memanggil metode CriteriaBuilder createQuery ()
  4. Membuat sebuah instance dari Query dengan memanggil Sesi createQuery () metode
  5. Panggil metode getResultList () dari objek kueri yang memberi kita hasilnya

Sekarang kita telah membahas dasar-dasarnya, mari beralih ke beberapa fitur kueri kriteria:

3.1. Menggunakan Ekspresi

The CriteriaBuilder dapat digunakan untuk membatasi hasil query berdasarkan kondisi tertentu. Dengan menggunakan metode CriteriaQuery where () dan memberikan Ekspresi yang dibuat oleh CriteriaBuilder.

Berikut beberapa contoh Ekspresi yang umum digunakan :

Untuk mendapatkan barang dengan harga lebih dari 1000:

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

Selanjutnya, mendapatkan item yang memiliki itemPrice kurang dari 1000:

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

Item yang memiliki itemNames berisi Kursi :

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

Catatan memiliki itemPrice di antara 100 dan 200:

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

Untuk memeriksa apakah properti yang diberikan adalah null:

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

Untuk memeriksa apakah properti yang diberikan bukan null:

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

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

Now inevitably the question comes, whether we can combine two or more of the above comparisons or not. The answer is, of course, yes – the Criteria API allows us to easily chain expressions:

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:

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

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

In the following example we order the list in an ascending order of the name and then in a 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

So far we have covered most of the basic topics. Now let's have a look at the different aggregate functions:

Get row count:

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

The following is an example of aggregate functions:

Aggregate function for Average:

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

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

3.4. CriteriaUpdate

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

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

CriteriaUpdate criteriaUpdate = cb.createCriteriaUpdate(Item.class); Root 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 from the CriteriaBuilder and use its set() method to provide new values for the itemPrice. To update multiple properties, we just need to call the set() method multiple times.

3.5. CriteriaDelete

CriteriaDelete, as its name implies, enables a delete operation using the Criteria API. All we need is to create an instance of CriteriaDelete and use the where() method to apply restrictions:

CriteriaDelete criteriaDelete = cb.createCriteriaDelete(Item.class); Root 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

In the previous sections we've 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.

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.

There are of course some disadvantages as well, especially around more complex joins.

So, generally speaking, we'll 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.

5. Conclusion

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

Kode yang dibahas di sini tersedia di repositori Github.