2012-08-09 6 views
83

Nun, die Frage sagt so ziemlich alles. JPAR-Repository verwenden Wie aktualisiere ich eine Entität?Wie aktualisiere ich eine Entität mit spring-data-jpa?

JPARepository hat nur eine speichern Methode, die mir nicht sagen, ob es tatsächlich erstellen oder zu aktualisieren ist. Zum Beispiel füge ich ein einfaches Objekt in der Datenbank Benutzer, die drei Felder hat: Vorname und Nachname und Alter:

@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 einfach ich „retten“, die an dieser Stelle ein Einsatz tatsächlich 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); 

Ok, alles ist gut. Jetzt möchte ich diesen Benutzer aktualisieren, sagen Sie ändern Sie sein Alter. Nun, ich könnte eine Query für diese entweder QueryDSL oder NamedQuery, was auch immer. Aber wenn ich bedenke, dass ich nur spring-data-jpa und das JPAR-Repository verwenden möchte, wie kann ich dann sagen, dass ich anstelle einer Einfügung ein Update machen möchte?

Genau wie sage ich Spring-Data-jpa, dass Benutzer, die den gleichen Benutzernamen und Vorname haben, tatsächlich gleich sind und dass es die Entität aktualisieren soll. Overriding Equals hat nicht funktioniert.

Vielen Dank!

+1

Sind Sie sicher, dass die ID neu geschrieben wird, wenn Sie ein bestehendes Objekt in der Datenbank speichern ?? Hatte das nie auf meinem Projekt tbh –

+0

@ByronVoorbach yup du hast recht, nur getestet. Update die Frage auch, thx – Eugene

+1

Hallo Freund, Sie können diesen Link http://StackOverflow.com/Questions/24420572/update-or-Saveorupdate-in-Crudrespository-is-there-any-options-Verfügbar Sie können ein sein Ansatz wie saveOrUpdate() – ibrahimKiraz

Antwort

107

Identität von Entitäten wird durch ihre Primärschlüssel definiert. Da firstname und lastname keine Teile des Primärschlüssels sind, können Sie JPA nicht anweisen, User s mit denselben firstname s und lastname s als gleich zu behandeln, wenn sie unterschiedliche userId s haben.

Also, wenn Sie einen User durch seine firstname und lastname identifiziert aktualisieren möchten, müssen Sie das User von einer Abfrage finden, und dann die entsprechenden Felder der Ihr gefundenes Objekt ändern. Diese Änderungen werden am Ende der Transaktion automatisch in die Datenbank übertragen, sodass Sie diese Änderungen nicht explizit speichern müssen.

EDIT:

Vielleicht sollte ich auf die allgemeine Semantik von JPA erarbeiten. Es gibt zwei Hauptansätze der Persistenz APIs zu entwerfen:

  • insert/update Ansatz. Wenn Sie die Datenbank ändern müssen, sollten Sie Methoden der Persistenz-API explizit aufrufen: Sie rufen insert auf, um ein Objekt einzufügen, oder update, um den neuen Zustand des Objekts in der Datenbank zu speichern.

  • Arbeitseinheit Ansatz. In diesem Fall haben Sie eine Reihe von Objekten verwaltet von Persistenz-Bibliothek. Alle Änderungen, die Sie an diesen Objekten vornehmen, werden automatisch am Ende der Arbeitseinheit (d. H. Am Ende der aktuellen Transaktion im typischen Fall) in die Datenbank übertragen. Wenn Sie einen neuen Datensatz in die Datenbank einfügen müssen, machen Sie das entsprechende Objekt verwaltet. Verwaltete Objekte werden durch ihre Primärschlüssel identifiziert. Wenn Sie also ein Objekt mit vordefiniertem Primärschlüssel verwaltet erstellen, wird es dem Datenbankdatensatz derselben ID zugeordnet, und der Status dieses Objekts wird an diesen Datensatz weitergegeben automatisch.

JPA folgt dem späteren Ansatz. save() im Frühjahr Daten JPA wird von merge() in plain JPA unterstützt, daher macht es Ihre Entität verwaltet wie oben beschrieben. Dies bedeutet, dass das Aufrufen von save() für ein Objekt mit vordefinierter ID den entsprechenden Datenbankdatensatz aktualisiert, anstatt einen neuen Datensatz einzufügen. Außerdem wird erläutert, warum save() nicht create() heißt.

+0

gut ja ich denke, ich weiß das. Ich habe mich streng auf Spring-Data-jpa bezogen. Ich habe jetzt zwei Probleme mit dieser Antwort: 1) Geschäftswerte sollten nicht Teil des Primärschlüssels sein - das ist bekannt, oder? Also ist der Vorname und der Nachname als Primärschlüssel nicht gut. Und 2) Warum heißt diese Methode dann nicht create, sondern speichere stattdessen in spring-data-jpa? – Eugene

+0

@Eugene: Aktualisiert. – axtavt

+0

"save() im Frühjahr Daten JPA wird von merge() in JPA" unterstützt "Haben Sie sich den Code angesehen? Ich habe es einfach getan und es wurde entweder durchhalten oder verschmelzen. Es wird basierend auf dem Vorhandensein der ID (Primärschlüssel) beibehalten oder aktualisiert. Dies sollte, denke ich, in der Save-Methode dokumentiert werden. So speichern ist eigentlich entweder zusammenführen oder bestehen. – Eugene

52

Da die Antwort von @axtavt konzentriert sich auf JPA nicht spring-data-jpa

Um ein Objekt zu aktualisieren, indem Sie die Abfrage dann ist das Speichern nicht effizient, weil es zwei Abfragen erfordert und möglicherweise die Abfrage kann sehr teuer sein, da es andere Tabellen beitreten kann und Laden Sie alle Sammlungen, die haben fetchType=FetchType.EAGER

Spring-data-jpa unterstützt Update-Vorgang.
Sie müssen die Methode in der Repository-Schnittstelle definieren und mit @Query und @Modifying annotieren.

@Modifying 
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3") 
void setUserInfoById(String firstname, String lastname, Integer userId); 

@Query ist für benutzerdefinierte Abfrage zu definieren und @Modifying ist für spring-data-jpa zu sagen, dass diese Abfrage ist ein Aktualisierungsvorgang, und es erfordert executeUpdate() nicht executeQuery().

+0

hey es funktioniert nicht! – bks4line

+2

Stellen Sie sicher, dass Sie es in der Transaktion ausführen – hussachai

+1

Hey! Danke, benutze Frühlingsdaten Bohnen. So wird es sich automatisch um mein Update kümmern. S speichern (S-Entität); kümmert sich automatisch um das Update. Ich musste deine Methode nicht benutzen! Trotzdem danke! – bks4line

4

Mit Feder-Daten-JPA speichern(), Ich hatte das gleiche Problem wie @DtechNet. Ich meine, jeder save() erstellte ein neues Objekt anstelle eines Updates. Um dies zu lösen, musste ich "Version" zu Entity und zugehöriger Tabelle hinzufügen.

1

Dies ist, wie ich das Problem gelöst:

User inbound = ... 
User existing = userRepository.findByFirstname(inbound.getFirstname()); 
if(existing != null) inbound.setId(existing.getId()); 
userRepository.save(inbound);