Nun, die Frage sagt so ziemlich alles. Wie aktualisiere ich mit JPARepository eine Entität?
JPARepository hat nur eine Speichermethode , die mir nicht sagt, ob es tatsächlich erstellt oder aktualisiert wird. Zum Beispiel füge ich ein einfaches Objekt in den Datenbankbenutzer ein, das drei Felder enthält : firstname
, lastname
und 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;
}
}
Dann rufe ich einfach auf save()
, was an dieser Stelle eigentlich eine Einfügung in die Datenbank ist:
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);
So weit, ist es gut. Jetzt möchte ich diesen Benutzer aktualisieren, beispielsweise sein Alter ändern. Zu diesem Zweck könnte ich eine Abfrage verwenden, entweder QueryDSL oder NamedQuery, was auch immer. Aber wenn ich bedenke, dass ich nur spring-data-jpa und das JPARepository verwenden möchte, wie kann ich dann sagen, dass ich anstelle einer Einfügung ein Update durchführen möchte?
Wie kann ich spring-data-jpa konkret mitteilen, dass Benutzer mit demselben Benutzernamen und Vornamen tatsächlich GLEICH sind und dass die vorhandene Entität aktualisiert werden soll? Das Überschreiben von Gleichen hat dieses Problem nicht gelöst.
quelle
Antworten:
Die Identität von Entitäten wird durch ihre Primärschlüssel definiert. Da
firstname
undlastname
nicht Teil des Primärschlüssels sind, können Sie JPA nicht anweisen,User
s mit denselbenfirstname
s undlastname
s als gleich zu behandeln, wenn sie unterschiedlich sinduserId
s haben.Wenn Sie also ein
User
durch seinfirstname
und identifiziertes Objekt aktualisieren möchtenlastname
, müssen Sie diesUser
durch eine Abfrage ermitteln und dann die entsprechenden Felder des gefundenen Objekts ändern. Diese Änderungen werden am Ende der Transaktion automatisch in die Datenbank übertragen, sodass Sie nichts tun müssen, um diese Änderungen explizit zu speichern.BEARBEITEN:
Vielleicht sollte ich die Gesamtsemantik von JPA näher erläutern. Es gibt zwei Hauptansätze für das Design von Persistenz-APIs:
Ansatz einfügen / aktualisieren . Wenn Sie die Datenbank ändern müssen, sollten Sie die Methoden der Persistenz-API explizit aufrufen: Sie rufen
insert
auf, um ein Objekt einzufügen oderupdate
den neuen Status des Objekts in der Datenbank zu speichern.Ansatz der Arbeitseinheit . In diesem Fall verfügen Sie über eine Reihe von Objekten, die von der Persistenzbibliothek verwaltet werden. Alle Änderungen, die Sie an diesen Objekten vornehmen, werden am Ende der Arbeitseinheit (dh im typischen Fall am Ende der aktuellen Transaktion) automatisch in die Datenbank übertragen. Wenn Sie neue Datensatz in die Datenbank einfügen müssen, stellen Sie das entsprechende Objekt verwaltet . Verwaltete Objekte werden anhand ihrer Primärschlüssel identifiziert. Wenn Sie also ein Objekt mit vordefiniertem Primärschlüssel verwalten , wird es dem Datenbankdatensatz mit derselben ID zugeordnet, und der Status dieses Objekts wird automatisch an diesen Datensatz weitergegeben.
JPA folgt dem letzteren Ansatz.
save()
In Spring Data wird JPA durchmerge()
einfaches JPA unterstützt, sodass Ihre Entität wie oben beschrieben verwaltet wird. Dies bedeutet, dass beim Aufrufensave()
eines Objekts mit vordefinierter ID der entsprechende Datenbankdatensatz aktualisiert wird, anstatt einen neuen einzufügen, und auch erklärt wird, warumsave()
nicht aufgerufen wirdcreate()
.quelle
extends CrudRepository<MyEntity, Integer>
anstattextends CrudRepository<MyEntity, String>
wie es hätte sein sollen. Hilft das? Ich weiß, dass dies fast ein Jahr später ist. Hoffe es hilft jemand anderem.Da konzentriert sich die Antwort von @axtavt
JPA
nicht daraufspring-data-jpa
Das Aktualisieren einer Entität durch Abfragen und Speichern ist nicht effizient, da zwei Abfragen erforderlich sind und die Abfrage möglicherweise recht teuer sein kann, da sie möglicherweise anderen Tabellen beitritt und alle vorhandenen Sammlungen lädt
fetchType=FetchType.EAGER
Spring-data-jpa
unterstützt den Update-Vorgang.Sie müssen die Methode in der Repository-Schnittstelle definieren
@Query
und mit und kommentieren@Modifying
.@Query
dient zum Definieren einer benutzerdefinierten Abfrage und@Modifying
zum Feststellen,spring-data-jpa
dass es sich bei dieser Abfrage um eine Aktualisierungsoperation handelt und diesexecuteUpdate()
nicht erforderlich istexecuteQuery()
.Sie können andere Rückgabetypen angeben:
int
- Die Anzahl der Datensätze, die aktualisiert werden.boolean
- true, wenn ein Datensatz aktualisiert wird. Ansonsten falsch.Hinweis : Führen Sie diesen Code in einer Transaktion aus .
quelle
To update an entity by querying then saving is not efficient
Dies sind nicht die einzigen beiden Möglichkeiten. Es gibt eine Möglichkeit, die ID anzugeben und das Zeilenobjekt abzurufen, ohne es abzufragen. Wenn Sie einrow = repo.getOne(id)
und dannrow.attr = 42; repo.save(row);
ausführen und die Protokolle anzeigen, wird nur die Aktualisierungsabfrage angezeigt.Sie können diese Funktion einfach mit der JPA-Funktion save () verwenden, aber das als Parameter gesendete Objekt muss eine vorhandene ID in der Datenbank enthalten, da dies sonst nicht funktioniert, da save () beim Senden eines Objekts ohne ID direkt eine Zeile hinzufügt Datenbank, aber wenn wir ein Objekt mit einer vorhandenen ID senden, werden die bereits in der Datenbank gefundenen Spalten geändert.
quelle
Wie bereits von anderen erwähnt, ist die
save()
enthält selbst sowohl einen Erstellungs- als auch einen Aktualisierungsvorgang.Ich möchte nur eine Ergänzung darüber hinzufügen, was hinter dem steht
save()
Methode .Lassen Sie uns zunächst die Erweiterungs- / Implementierungshierarchie der
CrudRepository<T,ID>
,Ok, überprüfen wir die
save()
Implementierung unterSimpleJpaRepository<T, ID>
,Wie Sie sehen können, wird zunächst geprüft, ob die ID vorhanden ist oder nicht. Wenn die Entität bereits vorhanden ist, erfolgt die Aktualisierung nur nach
merge(entity)
Methode. Andernfalls wird nach Methode ein neuer Datensatz eingefügtpersist(entity)
.quelle
Mit spring-data-jpa
save()
hatte ich das gleiche Problem wie @DtechNet. Ich meine, jeder hatsave()
ein neues Objekt erstellt, anstatt es zu aktualisieren. Um dies zu lösen, musste ich derversion
Entität und der zugehörigen Tabelle ein Feld hinzufügen .quelle
So habe ich das Problem gelöst:
quelle
@Transaction
obige Methode für mehrere Datenbankanforderungen. Eine in diesem Fall nicht benötigteuserRepository.save(inbound);
Änderung wird automatisch gespült.Federdaten
save()
Datenmethode hilft Ihnen dabei, beides auszuführen: Hinzufügen eines neuen Elements und Aktualisieren eines vorhandenen Elements.Rufen Sie einfach an
save()
und genießen Sie das Leben :))quelle
Id
Daten speichere, wie kann ich das Speichern neuer Datensätze vermeiden?quelle
Zu diesem speziellen Zweck kann man einen zusammengesetzten Schlüssel wie folgt einführen:
Kartierung:
So verwenden Sie es:
JpaRepository würde so aussehen:
Dann könnten Sie die folgende Redewendung verwenden: DTO mit Benutzerinformationen akzeptieren, Name und Vorname extrahieren und UserKey erstellen, dann eine UserEntity mit diesem zusammengesetzten Schlüssel erstellen und dann Spring Data save () aufrufen, das alles für Sie aussortieren soll.
quelle