web-dev-qa-db-fra.com

Requête nommée avec paramètre d'entrée

J'apprends JPA avec Hibernate, en utilisant maven également. Mon problème est: comment utiliser les paramètres d'entrée avec les clauses UPDATE et SET dans une requête nommée?

 @NamedQuery(name = "updateEmailAddress", query = "Update User u set u.email = :email where u.username = :username")

Cela me donne une erreur qu'un paramètre ne peut être utilisé que dans la clause WHERE ou HAVING. J'ai référé plusieurs articles mais je ne parviens toujours pas à trouver la solution appropriée. 

5
WC Madhubhashini

Dans JPA 2.0 et inférieur, les paramètres ne sont pas autorisés dans la clause set d'une requête nommée. seulement les littéraux. Cette limitation est levée si vous utilisez JPA 2.1. 

D'après ce que je peux comprendre, vous n'utilisez pas JPA 2.1. Par conséquent, je vais vous donner deux façons de contourner cette limitation. 

Option 1: Utilisez la méthode createQuery et transmettez-lui une chaîne générée dynamiquement. 

    String queryString = generateQueryString(email, username);
    entityManager.createQuery(queryString).executeUpdate();

Option 2: Mettez à jour l'entité associée et fusionnez. 

    List<User> result = entityManager.createQuery('select u from user u where 
    u.username = :username').setParameter('username', username).getResultList(); 
    for (User user : result) {
        user.setEmail(email);
        entityManager.merge(user);
    }

Option 3: Créez la requête en utilisant HQL et non pas JPQL. Je ne l'ai pas testé et je ne le recommande pas, car vous allez derrière le dos du responsable de l'entité. 

    Query q = sessionFactory.getCurrentSession().createNamedQuery('updateEmailAddress');
    q.setParameter('email', email);
    q.setParameter('username', username);
    q.executeUpdate();
7
Xavier Hammond

Jusqu'en JPA 2.1, cela n'était pas autorisé, mais vous pouvez l'utiliser car les fournisseurs vous laisseront fournir les paramètres de cette manière (ce qui s'avère être une bonne chose!).

Il semble que les fournisseurs JPA ne se conforment pas à la spécification concernant cette validation, et je pense que c'est simplement parce que cela n'avait aucun sens (vous pouvez voir que cela est maintenant autorisé en 2.1). "Pourquoi devrais-je rendre la tâche difficile aux développeurs?"

J'utilise également EclipseLink 2.3.1 et cela fonctionne bien.

La solution recommandée

Il suffit de désactiver la validation de requête JPQL d'Eclipse. 

Si le fournisseur l'accepte, ça devrait aller, sinon vous devez vous conformer à la spécification. Très simple. Le code sera plus propre et sera conforme aux évaluations récentes de la spécification.

Allez simplement à:Preferences > Java Persistence > JPA > Errors/Warnings > Queries and Generators > Invalid or incomplete JPQL queries:et Ignore it

Vérifiez cet article pour plus de détails:

Conclusion

Hibernate ne suit pas la spécification sur ce point, mais un Pourrait deviner que la nouvelle version de la spécification JPA autorisera ce comportement Comme indiqué dans le projet de JSR. JBoss Tools est probablement En train de valider la requête par rapport à la grammaire JPQL qui est basée sur la spécification Et affiche donc une erreur de validation.

Et voici la résolution:

Fin de la remarque

Après une discussion en équipe, nous avons décidé de conserver la mise en œuvre actuelle de Malgré le non-respect des spécifications. Changer le comportement Signifierait concaténation de chaînes ou substitution de chaînes pour Construire la requête et l’approche actuelle est beaucoup plus nette. Comme nous ne voyons pas D'indication d'un changement de fournisseur de persistance ou de serveur d'applications À ce stade, nous pensons que les avantages de la conservation du code sont supérieurs à Les risques à ce stade.

1
BonanzaOne

Vous devez créer une requête nommée comme suit:

Query query = getEntityManager().createNamedQuery("updateEmailAddress");

query.setParameter("email", "[email protected]");
query.setParameter("username", "emailuser");

int result = query.executeUpdate();
System.out.println("Rows affected: " + result);

Sources:

0
Carlos Laspina

Pouvez-vous essayer le paramètre de position et voir si cela fonctionne?

@NamedQuery(name = "updateEmailAddress", query = "UPDATE User u SET u.email = ?1 WHERE u.username = ?2")

//The parameter needs to be passed as
query.setParameter(1, "the_emailaddress");
query.setParameter(2, "the_username");
0
zapping