2
votes

Spring Data Rest: Limiter l'envoi de valeurs sur la méthode de mise à jour

J'ai implémenté par projet en utilisant Spring-Data-Rest. J'essaye de faire une mise à jour sur un enregistrement existant dans une table. Mais lorsque j'essaie d'envoyer seulement quelques champs au lieu de tous les champs (présents dans la classe Entity) via ma demande, Spring-Data-Rest pense que j'envoie des valeurs nulles / vides. Enfin, lorsque je vais voir la base de données, les champs que je n'envoie pas via ma demande sont remplacés par des valeurs nulles / vides. Donc, je crois comprendre que même si je n'envoie pas ces valeurs, Spring Data Rest les voit dans la classe Entity et envoie ces valeurs comme nulles / vides. Ma question ici est la suivante: existe-t-il un moyen de désactiver les champs lors de la mise à jour que je n'envoie pas via la demande. Je vous remercie de votre aide.

Mise à jour: j'utilisais la méthode PUT. Après avoir lu les commentaires, je l'ai changé en PATCH et cela fonctionne parfaitement maintenant. Appréciez toute l'aide


7 commentaires

au lieu d'utiliser la méthode put use patch


Ceci n'est pas lié aux données du printemps; c'est ainsi que fonctionne JPA / Hibernate. Si vous essayez de mettre à jour en passant une entité, tous les champs non renseignés seront considérés comme nuls et la mise à jour sera donc nulle. Vous devriez utiliser HQL o JPQL à la place


Quelle méthode HTTP utilisez-vous pour mettre à jour votre entité? PUT ou PATCH?


@ Cerp0 cela dépend de vos besoins, PUT a pour objectif principal de "mettre" toute la ressource quelque part (tous les champs d'une entité), et PATCH enverra simplement les valeurs dont vous avez besoin pour "patcher" quelque chose (juste un ou deux champs de l'entité par exemple)


@AngeloImmediata Bien que JPA / Hibernate puisse également utiliser une telle sémantique, compte tenu des mises à jour via PUT , c'est le Spécification HTTP qui déclare en fait qu'une charge utile reçue via PUT doit remplacer la représentation actuelle. Donc Spring fait exactement ce que la spécification entend


Bien que PATCH soit probablement le meilleur moyen d'obtenir des mises à jour partielles via HTTP, la correction de certaines ressources nécessite en fait que le client calcule les étapes nécessaires qu'un serveur doit appliquer au préalable et envoie ces instructions au client. Bien que le Patch de fusion JSON soit probablement la chose la plus proche de ce que vous voulez faire, vous ne devez appliquer cela si le client envoie la charge utile pour une représentation application / merge-patch + json mais pas pour d'autres représentations, comme application / json


@RomanVottner: Je suis tout à fait d'accord que dans un scénario parfaitement orienté RESY, les mises à jour doivent être effectuées en utilisant PUT . Ce que je voulais dire (et peut-être étais-je trop rapide ou direct), c'est que même si PUT est utilisé, côté serveur, nous avons un objet et JPA / Hibernate, et donc Spring, gérera cet objet . Si l'objet a des champs nuls ou vides, la mise à jour définira ces champs comme nulles. La question était de savoir pourquoi les champs nuls de spring-data set. Ceci n'est pas lié aux données de ressort ou à la méthode PUT . Simplement s'il y a des champs nuls, JPA / Hibernate essaiera de les définir null


3 Réponses :


1
votes

Avant la mise à jour, chargez l'objet à partir de la base de données, en utilisant la méthode jpa findById return object call target . Copiez ensuite tous les champs qui ne sont pas nuls / vides de object-want-to-update vers target , puis enregistrez enfin l'objet target .

Voici un exemple de code:

public void update(Object objectWantToUpdate) {

    Object target = repository.findById(objectWantToUpdate.getId());
    copyNonNullProperties(objectWantToUpdate, target);

    repository.save(target);
}

public void copyNonNullProperties(Object source, Object target) {
    BeanUtils.copyProperties(source, target, getNullPropertyNames(source));
}

public String[] getNullPropertyNames (Object source) {

    final BeanWrapper src = new BeanWrapperImpl(source);
    PropertyDescriptor[] propDesList = src.getPropertyDescriptors();

    Set<String> emptyNames = new HashSet<String>();

    for(PropertyDescriptor propDesc : propDesList) {
        Object srcValue = src.getPropertyValue(propDesc.getName());

        if (srcValue == null) {
            emptyNames.add(propDesc.getName());
        }
    }

    String[] result = new String[emptyNames.size()];
    return emptyNames.toArray(result);
}


1 commentaires

Merci @Tran Quoc Vu, j'aime ta réponse. Pour l'instant, je n'utilise pas cette solution car elle implique l'ajout d'un nouveau contrôleur personnalisé. Je vais utiliser PATCH au lieu d'utiliser PUT pour le moment. Mais je pourrais y revenir si je vois l'utilisation d'un contrôleur personnalisé.



0
votes

Vous pouvez écrire une requête de mise à jour personnalisée qui ne met à jour que des champs particuliers:

@Override
public void saveManager(Manager manager) {  
    Query query = sessionFactory.getCurrentSession().createQuery("update Manager set username = :username, password = :password where id = :id");
    query.setParameter("username", manager.getUsername());
    query.setParameter("password", manager.getPassword());
    query.setParameter("id", manager.getId());
    query.executeUpdate();
}


0 commentaires

0
votes

Comme certains des commentaires l'ont souligné, l'utilisation de PATCH au lieu de PUT a résolu le problème. Appréciez toutes les entrées. Ce qui suit est tiré de la documentation Spring Data Rest:

"La méthode PUT remplace l'état de la ressource cible par le corps de requête fourni.

La méthode PATCH est similaire à la méthode PUT mais met partiellement à jour l'état des ressources. "

https://docs.spring.io/spring-data/rest/docs/current/reference/html/#customizing-sdr.hiding-repository-crud-methods

De plus, j'aime la réponse @Tran Quoc Vu mais je ne l'implémente pas pour l'instant car je n'ai pas besoin d'utiliser de contrôleur personnalisé. S'il y a une logique (ex: validation) impliquée lors de la mise à jour de l'entité, je suis en faveur de l'utilisation du contrôleur personnalisé.


0 commentaires