web-dev-qa-db-fra.com

Spring Data JPA: Comment mettre à jour un modèle avec élégance?

  1. Mon modèle est comme ça:

    @Entity
    @Table(name = "user")
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Column(name="email")
        private String email;
    
        @Column(name = "weblink")
        private String webLink;
    
        //getter & setter
    }
    
  2. nous collectons des données de formulaire ou mobiles via une requête http, et springmvc transmettra ces données à un utilisateur similaire à Model.

    par exemple, j'ai une requête comme celle-ci:

    http://localhost:8080/update?id=1919&[email protected]

  3. dans contoller, l’URL de la requête et ses paramètres seront automatiquement transférés en un objet User.

    @RequestMapping(method = RequestMethod.GET, value = "/update0")
    public User update(@ModelAttribute("User") User user){
    
        System.out.println(user.getId());
        System.out.println(user.getEmail());
        System.out.println(user.getWebLink());
    
        return userRepository.save(test);
    }
    
  4. si j'ai un enregistrement dans mysql dont l'id est 1919, et les colonnes (id, email, weblik) sont toutes des valeurs.

    comme vous le voyez, l'objet utilisateur qui est passé par web ou mobile a deux propriétés

    http://localhost:8080/update?id=1919&[email protected]

    id et email ont des valeurs et weblink n'en ont pas.

    Donc, si j'exécute la méthode save, les colonnes email seront mises à jour à [email protected], et le champ weblik sera également mis à jour à NULL, mais je ne veux pas mettre à jour ce champ, je veux simplement mettre à jour le champ email.

  5. J'ai deux façons de résoudre le problème, mais toutes ne sont pas élégantes.

    5.1 chargez d'abord l'objet utilisateur et mettez-le à jour

    User userExist = userRepository.findOne(user.getId());
    userExist.setEmail(user.getEmail());
    
    //or using 
    //BeanUtil.copyProprty(formDto,modle)
    
    userRepository.save();
    

    5.2 en utilisant @DynamicUpdate, mais cela ne fonctionne pas.

    Existe-t-il un autre moyen de mettre à jour le modèle utilisateur sans effectuer de travail supplémentaire?.

    Merci d'avance.

9
diligent

La méthode la plus simple consiste à configurer le contrôleur de manière appropriée:

@RequestMapping(value = "/users/{user}", method = RequestMethod.PATCH)
public … updateUser(@ModelAttribute User user) { … }

Selon la documentation de référence lorsque cette méthode est appelée, les étapes suivantes se produisent:

  1. Une instance de User doit être obtenue. Cela nécessite en principe que Converter de String à User soit enregistré auprès de Spring MVC pour convertir le segment de chemin extrait du modèle d'URI en User. Si vous êtes par exemple en utilisant Spring Data et activez son support Web comme décrit dans sa documentation de référence , cela fonctionnera immédiatement.
  2. Une fois l’instance existante obtenue, les données de la demande seront liées à l’objet existant.
  3. L'objet lié sera remis à la méthode.

Astuces supplémentaires

  • N'utilisez pas GET comme méthode HTTP pour les mises à jour. GET est défini comme une opération sûre (pas d'effets secondaires), contrairement à une mise à jour. PATCH est la méthode correcte ici, telle qu'elle est définie pour autoriser les mises à jour partielles d'une ressource existante.
  • Pour soumettre des données de formulaire dans les demandes PUT et PATCH, vous devez enregistrer un HttpPutFormContentFilter avec l'application telle que décrite here . J'ai déposé un problème avec Spring Boot pour l'enregistrer par défaut.
13
Oliver Drotbohm

Au début, je dois dire que la solution Patch de @Oliver Gierke est vraiment géniale.

Et dans mon projet précédent, ma solution est:
1. Créez une classe abstraite pour implémenter JpaRepository et la fonction save().
2. Dans la fonction de sauvegarde, obtenez l'entité à partir de la base de données. Cela n'existe pas, sauvegardez-le. Sinon, utilisez la réflexion pour extraire tous les champs NOT NULL de l'entité mise à jour et les définir dans l'entité à partir de la base de données. (il est similaire à ce que vous faites, mais je l'ai fait pour toutes les fonctions de sauvegarde)

0
Mavlarn