Pendahuluan

JPA (Java/Jakarta Persistence API) merupakan alat bantu yang cukup bagus di lingkungan bahasa Java untuk menangani masalah query terhadap database relasional dengan menggunakan konsep Object.

Walaupun berada di level spesifikasi, akan tetapi sangat memudahkan kita dalam melakukan query ke database dengan mindset object oriented.

Kalau kita menggunakan frameworknya Spring, maka JPA ini dibungkus lagi dalam library Spring Data JPA.


Kemudahannya

Kemudahan dari Spring Data JPA yang didalamnya ada spesifikasi JPA ini misalnya :

  • memudahkan dalam melakukan query ke database, hanya dengan menggunakan penamaan method/fungsi saja. Misalnya untuk menemukan mahasiswa berdasarkan nama mahasiswa, id, atau status, bisa dengan cara :

List findByName(String name);

List findByNameOrId(String name, String id);

List findByNameAndStatus(String name, String status);

List findByNameLike(String firstname);

Secara otomatis frameworknya Spring Data JPA melakukan parsing dan membuat query criteria dan melakukan eksekusi di database sesuai dengan nama method yang kita buat.

  • memudahkan kita dalam melakukan transaksi database dengan anotasi @Transactional.

  • memudahkan kita dalam melakukan query database dengan memanfaatkan attribute object dari entity, dengan bahasa Java Persistence Query Language (JPQL).

Contohnya :

@Query(“SELECT m FROM Mahasiswa m WHERE m.name LIKE :name”)
List findAllByMahasiswaName(@Param(“name”) String name );

Dengan mudahnya kita bisa melakukan query seperti layaknya kita menganggap table di database sebagai objek saja.


Apa permasalahan yang kita angkat ?

Permasalahannya ketika misalnya kita mempunyai requirement sbb :

  • Query ke database mahasiswa.
  • Querynya bisa berdasarkan nama, id, status, angkatan, jumlah sks yang diambil, atau IPK.
  • Querynya juga bisa opsional. Jadi walaupun query berdasarkan nama saja sudah cukup. Atau berdasarkan nama, id, status saja sudah cukup.
  • Akibatnya ada kemungkinan salah satu parameter diatas adalah null atau tidak ada nilainya.

Apakah ini bisa diselesaikan dengan penamaan method secara dynamic diatas, atau pakai JPQL ?

Ok, coba kita lihat solusi yang mungkin..



1. Pakai penamaan Method

Akhirnya kita buat method sbb :

List findAllByNamaAndIdAndStatusAndAngkatanAndSksAndIpk(String name, String id, String status, String angkatan, Integer sks, Double ipk);

Waaah panjang juga yaa..

Dengan cara diatas, kita bisa melakukan query mahasiswa dengan banyak parameter, sbb :

  • nama mahasiswa
  • id mahasiswa
  • status nya aktif, libur, DO, mengundurkan diri, dll.
  • angkatan mahasiswa, 2022, 2021, dll
  • jumlah sks yang diambil
  • ipk mahasiswa.

Tetapi sesuai dengan requirement di awal, maka bisa saja yang diquery atau yang dipassing adalah cuma 3 parameter saja, misalnya cuma nama, id, dan status mahasiswa.

Akibatnya parameter yang lain seperti angkatan, jumlah sks, dan ipk akan dipassing sebagai null atau String kosong

Hasilnya tentu saja akan salah, karena di dalam query yang otomatis dibuat oleh Spring JPA akan ikut menyertakan WHERE angkatan IS null and jumlahSks IS null and ipk is null.

Oleh karenanya maka yang mungkin adalah solusi ke 2.



2. Pakai Java Persistence Query Language (JPQL).

Dengan JPQL berarti kita bisa membuat sintaks query berdasarkan attribute dari objek yang dipetakan ke sebuah table di database

Contohnya :

@Query("SELECT m FROM Mahasiswa m WHERE m.name = :name AND m.id = :id AND m.status = :status AND m.angkatan = :angkatan AND m.sks = :sks AND m.ipk = :ipk")
List<Mahasiswa> findAllByCustom(@Param("name") String name, @Param("id") String id, @Param("status") String status, @Param("angkatan") String angkatan, @Param("sks") Integer sks, @Param("ipk") Double ipk);

Tapi tunggu, ini sama saja kan dengan konstruksi query seperti sebelummya yang memakai penamaan method ?

Sehingga kembali lagi kepada kasus kalau parameternya null atau kosong bagaimana ?

Ok..ok, dengan JPQL masalah ini bisa kita selesaikan dengan cara yang lebih mudah.

Secara umum , solusinya adalah dengan cara :

WHERE (:param1 IS NULL OR param1 = :param1) …….

yaitu dengan melakukan pembandingan apakah parameter yang dikirimkan adalah null.

Kalau null, maka querynya akan dilewatkan begitu saja.

Kalau ternyata ada, maka akan dilakukan filtering.


Jadi bagaimana dengan kasus diatas ?

Dengan demikian, kasus diatas bisa diubah dengan query sbb :

@Query("SELECT m FROM Mahasiswa m WHERE (:name is NULL OR m.name = :name) AND (:id IS NULL OR m.id = :id) AND (:status IS NULL OR m.status = :status) AND (:angkatan IS NULL OR m.angkatan = :angkatan) AND (:sks IS NULL OR m.sks = :sks) AND (:ipk IS NULL OR m.ipk = :ipk"))
List<Mahasiswa> findAllByCustom(@Param("name") String name, @Param("id") String id, @Param("status") String status, @Param("angkatan") String angkatan, @Param("sks") Integer sks, @Param("ipk") Double ipk);

Dengan cara seperti diatas, maka kita bisa dengan bebas mem-passing parameter null ke attribute-attribute diatas, dan tetap berjalan dengan benar.

Tanpa harus kita lakukan coding di sisi class repositorynya kita.