Jumat, 21 September 2012

JPA Query Language (JPAQL)

JPAQL adalah bahasa query JPA yang mirip dengan SQL. Bedanya, dalam JPAQL kita menggunakan nama object dan property, bukan nama tabel dan kolom.

Query Sederhana
Untuk contoh pertama, mari kita implementasikan ArticleDao.findAll().

public class ArticleDao {
public List<Article> findAll() {
return entityManager.createQuery(
“selct a from Article a”).getResultList();
}
}


Query di atas akan menghasilkan semua object Article yang ada
dalam database.


Pagination
Bila aplikasi kita menyimpan ribuan artikel, tentunya kita ingin mengambil data secara bertahap, halaman per halaman (paging). SQL yang digunakan untuk pagination ini biasanya berbeda antar database. Dengan JPA, kita bisa menggunakan satu JPAQL saja. JPA nantinya akan menerjemahkan sesuai dengan merek database yang kita gunakan.
Untuk mengambil artikel per halaman, kita overload method findAll agar menerima parameter startIndex dan pageSize. Parameter startIndex adalah index yang menunjukkan record pertama dalam halaman, sedangkan pageSize menunjukkan jumlah record per halaman.
Berikut overloading method findAll.

public List<Article> findAll
(int startIndex, int pageSize){
return entityManager
.createQuery("select a from Article a")
.setFirstResult(startIndex)
.setMaxResults(pageSize)
.getResultList();
}


Parameter Binding
Bagaimana kalau kita mau mengirim parameter ke query? JPA mendukung parameter binding, mirip dengan PreparedStatement di JDBC.
Bila kita ingin mengambil artikel yang ditulis pengarang tertentu, berikut kodenya.

public List<Article> findByAuthor(Author author) {
String query = "from Article a ";
query += " where a.author.id = :authorId ";
return entityManager
.createQuery(query)
.setParameter("authorId", author.getId())
.getResultList();
}


Selain itu, kita juga bisa menggunakan parameter bertipe java.util.Date. Contohnya bila kita ingin  mendapatkan artikel yang diterbitkan setelah tanggal tertentu. Buat method articlesPublishedAfter dalam ArticleDao.

public List<Article> articlesPublishedAfter
(Date publishDate) {
String query = "from Article a ";
query += "where a.publishDate > :publishDate";
return entityManager.createQuery(query)
.setParameter("publishDate", publishDate)
.getResultList();
}


Named Query
Kita bisa mengeluarkan JPAQL dari dalam objek DAO dan memindahkannya ke class Entity. Dari class DAO, kita cukup memanggil nama query tersebut. Fitur ini disebut Named Query. Misalnya, kita ingin mengambil artikel berdasarkan kategori. Berikut JPAQL-nya.

from Article a where a.category.id = :categoryId


JPAQL ini bisa kita letakkan dalam class Article. Berikut deklarasi class Article.
 
@Entity @Table(name = "T_ARTICLE")
@NamedQueries({
@NamedQuery(
name = "articleByCategory",
query = "from Article a "+
"where a.category.id = :categoryId"
)
})
public class Article { }


Named Query ini dipanggil dari ArticleDao dalam method findByCategory seperti ini.

public List<Article> findByCategory(Category category) {
return entityManager
.createNamedQuery("articleByCategory")
.setParameter("categoryId", category.getId())
.getResultList();
}


Restriction
Kita menggunakan restriction untuk membatasi jumlah record yang dihasilkan. Mirip dengan SQL, kita menggunakan keyword where untuk membatasi hasil query.
Contohnya, kita mengambil artikel yang diterbitkan setelah tanggal tertentu. JPAQLnya tampak seperti ini:

from Article a where a.publishDate > :publishDate

Hampir semua operator yang biasa kita gunakan di Java dapat digunakan. Berikut tabel operator yang didukung, diurutkan berdasarkan prioritas eksekusinya:
.                                                         navigasi object
+ -                                                     untuk membuat menjadi positif/negatif
* /                                                      perkalian dan pembagian
+ -                                                     penjumlahan dan pengurangan
= <>                                                  sama dengan atau tidak sama dengan
<, >, <=, >=                                       perbandingan
[NOT] BETWEEN, [NOT] LIKE,
[NOT] IN, IS [NOT] NULL              perbandingan, mirip dengan sintaks SQL
IS [NOT] EMPTY, [NOT]
MEMBER [OF]                                 pengecekan collection
NOT, AND, OR                                operator logika

Misalnya, bila kita ingin mengambil artikel yang bukan kategori Berita, query-nya seperti ini:

String jpaql = “from Article a “;
jpaql += “where a.category <> :category”;
List<Article> hasil =
entityManager.createQuery(jpaql).getResultList();


Kita menggunakan karakter % untuk menggantikan karakter apa saja dalam jumlah berapa saja. Misalnya, kita ingin mencari artikel yang diawali dengan huruf A, maka kita gunakan JPAQL seperti ini:

from Article a where a.title like 'A%'

Lalu bagaimana kalau kita ingin mencari artikel yang diawali dengan karakter %?
Gunakan escape character \, sehingga JPAQLnya menjadi seperti ini:

from Article a where a.title like '\%'

Bila kita menggunakan lebih dari satu persyaratan, gunakan keyword and atau or sesuai kebutuhan. Contohnya, kita ingin mencari artikel yang judulnya diawali huruf A, dan nama pengarangnya juga diawali dengan huruf A.

from Article a where a.title like 'A%'
and a.author.fullname like 'A%'


Contoh lain, bila kita ingin mencari artikel yang diawali huruf A dan juga huruf B, JPAQLnya seperti ini.

from Article a where a.title like 'A%'
or a.title like 'B%'


Kita bisa mengurutkan hasil pencarian dengan menggunakan keyword order by, sama seperti SQL.
Berikut contoh pengurutan artikel berdasarkan judulnya.

String jpaql = “from Article a “;
jpaql += “order by a.title asc ”;
List<Article> hasil =
entityManager.createQuery(jpaql).getResultList();


Kita menggunakan keyword asc, yang artinya ascending untuk mengurutkan dari kecil ke besar. Untuk urutan sebaliknya, gunakan keyword desc, yang artinya descending.

Query untuk Collection
Ada beberapa keyword yang dapat digunakan untuk memanipulasi collection. Misalnya, kita ingin mencari group yang tidak punya member.

from Group g where g.members is empty

Atau mencari user yang tergabung dalam grup dengan nama tertentu.

from User u, Group g where g.name=? and u member of g.members

Projection
Bila tadi kita sudah menentukan sumber data dengan keyword from dan batasan hasil dengan keyword where, sekarang kita bisa menentukan format hasil yang dikeluarkan dengan keyword
select.
Mari kita lihat lagi query user yang menjadi anggota grup.

from User u, Group g where g.name=? and u member of g.members

Pada query di atas, kita bisa memilih untuk hanya mengambil data user saja dengan menggunakan select. Query di atas bisa ditulis menjadi seperti ini:

select u
from User u, Group g
where g.name=? and u member of g.members


Dengan query seperti itu, kita bisa membuat method di class GroupDao sebagai berikut:

public List<User> membersOf(String groupName) {
String jpaql = "select u ";
jpaql += "from User u, Group g ";
jpaql += "where g.name = :groupName ";
jpaql += "and u member of g.members';
return entityManager
.createQuery(jpaql)
.setString("groupName", groupName)
.getResultList();
}


Join
JPA memiliki kemampuan untuk menggabungkan beberapa objek sekaligus. Sebagai contoh, kita ingin menampilkan nama penulis yang pernah mengisi artikel dengan kategori Headline News. Query ini melibatkan tiga objek, yaitu Author, Article, dan Category.

select au.fullname
from Article ar join ar.author as au
where ar.category .name like 'Headline%'


Query di atas akan menghasilkan beberapa record dengan nama yang sama. Untuk membuang hasil yang duplikat, gunakan keyword distinct.

select distinct au.fullname
from Article ar join ar.author as au
where ar.category.name like 'Headline%'


Report Query
Report query adalah query yang mengandalkan kemampuan database untuk melakukan agregasi terhadap data yang jumlahnya banyak. Biasanya report query banyak memanfaatkan aggregate function seperti sum, count, group by, dan having.
Sebagai contoh, bila kita ingin menghitung jumlah artikel yang sudah ditulis seorang author, kita bisa menggunakan query berikut.

select count (a)
from Article a
where a.author.fullname = 'endy'


Atau kita bisa juga menghitung berapa artikel yang tidak dikomentari pengunjung.

select count (a)
from Article a
where a.comments is empty


Subquery
JPA juga mendukung query di dalam query. Sebagai contoh, kita ingin menampilkan penulis mana yang pernah membuat artikel dengan nama kategori berakhiran News.

select distinct (au) 
from Author au, Article ar where ar.category.id in (select c.id from Category c where c.name like '%News')

Tidak ada komentar:

Posting Komentar