317 votes

Comment mettre à jour une entité en utilisant spring-data-jpa ?

La question dit à peu près tout. En utilisant JPARepository, comment mettre à jour une entité ?

JPARepository n'a qu'un sauver ce qui ne me permet pas de savoir s'il s'agit d'une création ou d'une mise à jour. Par exemple, j'insère un simple objet dans la base de données User, qui comporte trois champs : firstname , lastname et 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;
  }
}

Ensuite, j'appelle simplement save() qui, à ce stade, est en fait une insertion dans la base de données :

 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);

Jusqu'à présent, tout va bien. Maintenant, je veux mettre à jour cet utilisateur, par exemple changer son âge. Pour ce faire, je pourrais utiliser une requête, soit QueryDSL ou NamedQuery, peu importe. Mais, étant donné que je veux juste utiliser spring-data-jpa et le JPARepository, comment puis-je lui dire qu'au lieu d'une insertion, je veux faire une mise à jour ?

Plus précisément, comment puis-je dire à spring-data-jpa que les utilisateurs ayant le même nom d'utilisateur et le même prénom sont en fait ÉGAUX et que l'entité existante est censée être mise à jour ? La surcharge de equals n'a pas résolu ce problème.

289voto

axtavt Points 126632

L'identité des entités est définie par leurs clés primaires. Étant donné que firstname et lastname ne font pas partie de la clé primaire, vous ne pouvez pas demander à JPA de traiter les données User avec les mêmes firstname et lastname comme égaux s'ils ont des userId s.

Ainsi, si vous souhaitez mettre à jour un User identifiée par son firstname et lastname Vous devez trouver ce qui suit User par une requête, puis modifiez les champs appropriés de l'objet que vous avez trouvé. Ces modifications seront automatiquement transférées dans la base de données à la fin de la transaction, de sorte qu'il n'est pas nécessaire de les enregistrer explicitement.

EDITAR:

Je devrais peut-être préciser la sémantique générale de JPA. Il existe deux approches principales de la conception des API de persistance :

  • approche par insertion/mise à jour . Lorsque vous devez modifier la base de données, vous devez appeler explicitement les méthodes de l'API de persistance : vous appelez insert pour insérer un objet, ou update pour enregistrer le nouvel état de l'objet dans la base de données.

  • Approche par unité de travail . Dans ce cas, vous disposez d'un ensemble d'objets géré par la bibliothèque de persistance. Toutes les modifications apportées à ces objets seront automatiquement transférées dans la base de données à la fin de l'unité de travail (c'est-à-dire à la fin de la transaction en cours dans le cas typique). Lorsque vous devez insérer un nouvel enregistrement dans la base de données, vous créez l'objet correspondant géré . Géré sont identifiés par leurs clés primaires, de sorte que si vous créez un objet avec une clé primaire prédéfinie géré il sera associé à l'enregistrement de la base de données ayant le même identifiant, et l'état de cet objet sera automatiquement propagé à cet enregistrement.

JPA suit cette dernière approche. save() dans Spring Data JPA est soutenu par merge() en JPA simple, ce qui rend votre entité géré comme décrit ci-dessus. Cela signifie qu'appeler save() sur un objet avec un identifiant prédéfini mettra à jour l'enregistrement correspondant dans la base de données plutôt que d'en insérer un nouveau, et explique également pourquoi save() n'est pas appelé create() .

226voto

hussachai Points 3842

La réponse de @axtavt étant axée sur JPA no spring-data-jpa

La mise à jour d'une entité par interrogation puis enregistrement n'est pas efficace car elle nécessite deux requêtes et la requête peut être assez coûteuse car elle peut joindre d'autres tables et charger toutes les collections qui ont des données. fetchType=FetchType.EAGER

Spring-data-jpa prend en charge les opérations de mise à jour.
Vous devez définir la méthode dans l'interface du référentiel et l'annoter avec la mention @Query et @Modifying .

@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 permet de définir des requêtes personnalisées et @Modifying c'est pour dire spring-data-jpa que cette requête est une opération de mise à jour et qu'elle nécessite executeUpdate() no executeQuery() .

Vous pouvez spécifier le type de retour comme int avec le nombre d'enregistrements mis à jour.


Note : Exécutez ce code dans un Transaction .

56voto

Kalifornium Points 693

Vous pouvez simplement utiliser cette fonction avec la fonction JPA save(), mais l'objet envoyé en paramètre doit contenir un identifiant existant dans la base de données, sinon cela ne fonctionnera pas, car save() lorsque nous envoyons un objet sans identifiant, il ajoute directement une ligne dans la base de données, mais si nous envoyons un objet avec un identifiant existant, il modifie les colonnes déjà trouvées dans la base de données.

public void updateUser(Userinfos u) {
    User userFromDb = userRepository.findById(u.getid());
    // crush the variables of the object found
    userFromDb.setFirstname("john"); 
    userFromDb.setLastname("dew");
    userFromDb.setAge(16);
    userRepository.save(userFromDb);
}

46voto

upma Points 517

Comme cela a déjà été mentionné par d'autres, la save() contient à la fois des opérations de création et de mise à jour.

Je voudrais juste ajouter un complément sur ce qui se cache derrière le save() método.

Tout d'abord, voyons la hiérarchie extend/implement de l'élément CrudRepository<T,ID> , enter image description here

Ok, vérifions le save() la mise en œuvre à SimpleJpaRepository<T, ID> ,

@Transactional
public <S extends T> S save(S entity) {

    if (entityInformation.isNew(entity)) {
        em.persist(entity);
        return entity;
    } else {
        return em.merge(entity);
    }
}

Comme vous pouvez le voir, il vérifie d'abord si l'ID existe ou non. Si l'entité existe déjà, seule la mise à jour est effectuée par merge(entity) et si ce n'est pas le cas, un nouvel enregistrement est inséré par la méthode persist(entity) méthode.

12voto

Amir Mhp Points 107

Données du printemps save() vous aidera à effectuer les deux opérations : ajouter un nouvel élément et mettre à jour un élément existant.

Il suffit d'appeler le save() et profiter de la vie :))

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X