Query Dinamis pada Spring Boot JPA

Ada keunikan ketika kita meng-eksekusi fungsi save(...) pada Spring Boot JPA, yaitu pada query yang di eksekusi ke database bukanlah query dinamis yang hanya insert / update field-field yang kita isikan saja. Melainkan keseluruhan field yang ada di table tersebut. Hal ini bisa menyebabkan default value yang sudah di inisiasi dari sisi database tidak berjalan seperti yang seharusnya. Maka dari itu yang kita butuhkan adalah membuat dinamis query yang di eksekusi oleh fungsi save(...).

Asumsikan kita mempunya table seperti dibawah ini, dimana kita memiliki field last_login yang seharusnya akan terisi secara otomatis apabila ada row baru maupun melakukan update apabila ada perubahan data.

create table user(
	id int primary key auto_increment,
	name varchar(256) default null,
	address varchar(256) default null,
	last_login datetime default current_timestamp on update current_timestamp
);

Secara logika apabila kita ingin menambahkan data kita bisa meng-eksekusi query dibawah ini

insert into user (name, address) values ("Foo", "Bar");

Hasilnya akan menjadi seperti dibawah ini

IDNameAddressLast Login
1FooBar2021-02-13 09:33:48

Bagaimana dengan Spring Boot JPA ?

Bagi yang sudah berpengalaman mengimplementasi kelas entity dan repository bisa lanjut saja ke langkah selanjutnya, atau mulai dari sini. Dibawah ini adalah kelas entity biasa.

@Entity
@Table(name = "user")
data class User(

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    var id: Long? = null,

    @Column(name = "name")
    var name: String? = null,

    @Column(name = "address")
    var address: String? = null,

    @Column(name = "last_login")
    var lastLogin: Date? = null
)

Apabila di eksekusi dengan cara dibawah ini

fun add() {
    val data = User(name = "Foo", address = "Bar")
    userRepository.save(data)
}

Spring akan meng-eksekusi query berikut ke MySQL

insert into user (address, last_login, name) values (?, ?, ?)

Bagaimana mungkin last_login bisa di eksekusi, padahal kita tidak memanggilnya. Hal ini berdampak pada hasil di table, karena last_login di eksekusi padahal tidak dipanggil maka akan bernilai NULL artinya data di table akan bernilai NULL juga.

Solusi 1: Hapus Field di Kelas Entity

Dengan solusi ini, Spring tidak akan meng-eksekusi field yang tidak dikenalinya. Namun, dalam beberapa kasus, kita membutuhkan field tersebut, entah untuk validasi atau proses apapun. Maka, tidak bisa dipungkiri harus disertakan dalam kelas Entity.

Solusi 2: Gunakan anotasi

Dengan solusi ini, kita bisa gunakan anotasi khusus yang berfungsi sebagai transformasi query untuk menghilangkan field-field yang tidak dipanggil untuk tidak di eksekusi di query SQL. Ada dua anotasi yang bisa digunakan, yaitu @DynamicInsert dan @DynamicUpdate keduanya memiliki fungsi yang sama hanya berbeda proses saja, bisa dong ditebak perbedaan proses-nya.

@Entity
@Table(name = "user")
@DynamicInsert
@DynamicUpdate
data class User(
    ....
)

Jalankan aplikasi lagi, kemudian log query nya.

insert into user (address, name) values (?, ?)

Nah sudah sesuai dengan ekspektasi kita.

You Might Also Like