Yah pertanyaannya cukup banyak mengatakan segalanya. Menggunakan JPARepository, bagaimana cara saya memperbarui suatu entitas?
JPARepository hanya memiliki metode penyimpanan , yang tidak memberi tahu saya apakah itu benar-benar membuat atau memperbarui. Sebagai contoh, saya memasukkan Obyek sederhana untuk Pengguna database, yang memiliki tiga bidang: firstname
, lastname
dan age
:
@Entity
public class User {
private String firstname;
private String lastname;
//Setters and getters for age omitted, but they are the same as with firstname and lastname.
private int age;
@Column
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
private long userId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getUserId(){
return this.userId;
}
public void setUserId(long userId){
this.userId = userId;
}
}
Maka saya cukup menelepon save()
, yang pada saat ini sebenarnya adalah memasukkan ke dalam basis data:
User user1 = new User();
user1.setFirstname("john"); user1.setLastname("dew");
user1.setAge(16);
userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);
Sejauh ini baik. Sekarang saya ingin memperbarui pengguna ini, katakan ubah usianya. Untuk tujuan ini saya bisa menggunakan Query, baik QueryDSL atau NamedQuery, apa pun. Tetapi, mengingat saya hanya ingin menggunakan pegas-data-jpa dan JPARepository, bagaimana saya mengatakannya bahwa alih-alih memasukkan saya ingin melakukan pembaruan?
Secara khusus, bagaimana cara memberi tahu pegas-data-jpa bahwa pengguna dengan nama pengguna dan nama depan yang sama sebenarnya EQUAL dan bahwa entitas yang ada seharusnya diperbarui? Override sama dengan tidak menyelesaikan masalah ini.
sumber
Jawaban:
Identitas entitas didefinisikan oleh kunci utama mereka. Karena
firstname
danlastname
bukan bagian dari kunci utama, Anda tidak dapat memberi tahu JPA untuk memperlakukanUser
s denganfirstname
s danlastname
s yang sama jika mereka memilikiuserId
s yang berbeda .Jadi, jika Anda ingin memperbarui yang
User
diidentifikasi olehfirstname
danlastname
, Anda perlu menemukannyaUser
dengan kueri, lalu ubah bidang yang sesuai dari objek yang Anda temukan. Perubahan-perubahan ini akan dihapus ke database secara otomatis pada akhir transaksi, sehingga Anda tidak perlu melakukan apa pun untuk menyimpan perubahan ini secara eksplisit.EDIT:
Mungkin saya harus menguraikan semantik keseluruhan JPA. Ada dua pendekatan utama untuk merancang API persistensi:
masukkan / perbarui pendekatan . Ketika Anda perlu memodifikasi database Anda harus memanggil metode API kegigihan secara eksplisit: Anda menelepon
insert
untuk menyisipkan objek, atauupdate
untuk menyimpan keadaan objek yang baru ke database.Pendekatan Unit Kerja . Dalam hal ini Anda memiliki satu set objek yang dikelola oleh perpustakaan kegigihan. Semua perubahan yang Anda lakukan pada objek-objek ini akan disiram ke database secara otomatis di akhir Unit Kerja (yaitu pada akhir transaksi saat ini dalam kasus khusus). Saat Anda perlu menyisipkan catatan baru ke database, Anda membuat objek terkait dikelola . Objek yang dikelola diidentifikasi oleh kunci utama mereka, sehingga jika Anda membuat objek dengan kunci utama yang telah ditentukan sebelumnya dikelola , itu akan dikaitkan dengan catatan basis data dari id yang sama, dan keadaan objek ini akan disebarkan ke catatan itu secara otomatis.
JPA mengikuti pendekatan yang terakhir.
save()
di Spring Data JPA didukung olehmerge()
dalam JPA biasa, karena itu membuat entitas Anda dikelola seperti dijelaskan di atas. Ini berarti bahwa memanggilsave()
objek dengan id yang telah ditentukan akan memperbarui catatan database yang sesuai daripada memasukkan yang baru, dan juga menjelaskan mengapasave()
tidak dipanggilcreate()
.sumber
extends CrudRepository<MyEntity, Integer>
bukannyaextends CrudRepository<MyEntity, String>
seperti seharusnya. Apakah itu membantu? Saya tahu ini hampir setahun kemudian. Semoga ini bisa membantu orang lain.Karena jawaban oleh @axtavt berfokus pada
JPA
tidakspring-data-jpa
Untuk memperbarui entitas dengan kueri, maka menyimpan tidak efisien karena memerlukan dua kueri dan mungkin kueri bisa sangat mahal karena dapat bergabung dengan tabel lain dan memuat koleksi apa pun yang memiliki
fetchType=FetchType.EAGER
Spring-data-jpa
mendukung operasi pembaruan.Anda harus mendefinisikan metode dalam antarmuka Repositori. Dan menjelaskannya dengan
@Query
dan@Modifying
.@Query
adalah untuk mendefinisikan permintaan kustom dan@Modifying
bagi mengatakanspring-data-jpa
bahwa query ini adalah operasi update dan membutuhkanexecuteUpdate()
tidakexecuteQuery()
.Anda dapat menentukan jenis pengembalian lainnya:
int
- jumlah catatan yang diperbarui.boolean
- true jika ada catatan yang diperbarui. Kalau tidak, salah.Catatan : Jalankan kode ini dalam Transaksi .
sumber
To update an entity by querying then saving is not efficient
ini bukan hanya dua pilihan. Ada cara untuk menentukan id dan mendapatkan objek baris tanpa menanyakannya. Jika Anda melakukanrow = repo.getOne(id)
dan kemudianrow.attr = 42; repo.save(row);
dan menonton log, Anda hanya akan melihat permintaan pembaruan.Anda cukup menggunakan fungsi ini dengan fungsi save () JPA, tetapi objek yang dikirim sebagai parameter harus berisi id yang ada dalam database jika tidak maka tidak akan berfungsi, karena save () ketika kami mengirim objek tanpa id, ia menambahkan langsung satu baris dalam database, tetapi jika kami mengirim objek dengan id yang ada, itu mengubah kolom yang sudah ditemukan dalam database.
sumber
Seperti apa yang telah disebutkan oleh orang lain,
save()
itu sendiri berisi operasi buat dan perbarui.Saya hanya ingin menambahkan suplemen tentang apa di balik
save()
metode ini.Pertama, mari kita lihat hierarki extended / implement dari
CrudRepository<T,ID>
,Ok, mari kita periksa
save()
implementasinya diSimpleJpaRepository<T, ID>
,Seperti yang Anda lihat, itu akan memeriksa apakah ID ada atau tidak pertama, jika entitas sudah ada, hanya pembaruan yang akan terjadi dengan
merge(entity)
metode dan jika lain, catatan baru dimasukkan denganpersist(entity)
metode.sumber
Menggunakan spring-data-jpa
save()
, saya mengalami masalah yang sama dengan @DtechNet. Maksud saya setiapsave()
membuat objek baru alih-alih pembaruan. Untuk mengatasi ini saya harus menambahkanversion
bidang ke entitas dan tabel terkait.sumber
Inilah cara saya memecahkan masalah:
sumber
@Transaction
metode di atas untuk beberapa permintaan db. Dan dalam hal ini tidak perluuserRepository.save(inbound);
, perubahan memerah secara otomatis.save()
metode data pegas akan membantu Anda melakukan keduanya: menambahkan item baru dan memperbarui item yang ada.Panggil saja
save()
dan nikmati hidup :))sumber
Id
akan menyimpannya, bagaimana saya bisa menghindari menyimpan catatan baru.sumber
Untuk tujuan khusus ini orang dapat memperkenalkan kunci komposit seperti ini:
Pemetaan:
Berikut cara menggunakannya:
JpaRepository akan terlihat seperti ini:
Kemudian, Anda dapat menggunakan idiom berikut : terima DTO dengan info pengguna, ekstrak nama dan nama depan dan buat UserKey, lalu buat UserEntity dengan kunci komposit ini dan aktifkan Spring Data save () yang seharusnya memilah semuanya untuk Anda.
sumber