web-dev-qa-db-fra.com

La requête native avec paramètre nommé échoue avec "Tous les paramètres nommés n'ont pas été définis"

Je veux exécuter une requête native simple, mais cela ne fonctionne pas:

@Autowired
private EntityManager em;

Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = :username");
em.setProperty("username", "test");
(int) q.getSingleResult();

Pourquoi ai-je cette exception?

org.hibernate.QueryException: Not all named parameters have been set: [username]
43
membersound

Les paramètres nommés ne sont pas pris en charge par JPA dans les requêtes natives, uniquement pour JPQL. Vous devez utiliser des paramètres de position.

Les paramètres nommés respectent les règles relatives aux identificateurs définis dans la section 4.4.1. L'utilisation de paramètres nommés s'applique au Java langage de requête Persistence et n'est pas défini pour les requêtes natives. . Seule la liaison de paramètre de position peut être utilisée de manière portable pour les requêtes natives. .

Alors, utilisez ceci

Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");

Bien que la spécification JPA ne prenne pas en charge les paramètres nommés dans les requêtes natives, certaines implémentations JPA (telles que Hibernate ) peuvent la prendre en charge.

Les requêtes SQL natives prennent en charge les paramètres de position et les paramètres nommés

Toutefois, cela associe votre application à une implémentation JPA spécifique et la rend donc inutilisable.

79
Predrag Maric

Après plusieurs tentatives, j'ai trouvé que vous devriez utiliser createNativeQuery et vous pouvez envoyer des paramètres en utilisant # remplacement

Dans mon exemple

String UPDATE_lOGIN_TABLE_QUERY = "UPDATE OMFX.USER_LOGIN SET LOGOUT_TIME = SYSDATE WHERE LOGIN_ID = #loginId AND USER_ID = #userId";


Query query = em.createNativeQuery(logQuery);

            query.setParameter("userId", logDataDto.getUserId());
            query.setParameter("loginId", logDataDto.getLoginId());

            query.executeUpdate();
11
Ahmed Salem

J'utilise EclipseLink. Cette JPA autorise les requêtes suivantes de la manière suivante:

Query q = em.createNativeQuery("SELECT * FROM mytable where username = ?username");
q.setParameter("username", "test");
q.getResultList();
8
Jeff_Alieffson

Vous appelez setProperty au lieu de setParameter. Changez votre code en

Query q = em.createNativeQuery("SELECT count(*) FROM mytable where username = :username");
em.setParameter("username", "test");
(int) q.getSingleResult();

et ça devrait marcher.

7
oberlies

C'était un bogue corrigé dans la version 4.3.11 https://hibernate.atlassian.net/browse/HHH-2851

EDIT: La meilleure façon d'exécuter une requête native consiste à utiliser NamedParameterJdbcTemplate Cela vous permet de récupérer un résultat qui n'est pas une entité gérée; vous pouvez utiliser un RowMapper et même un mappage de paramètres nommés !

private NamedParameterJdbcTemplate namedParameterJdbcTemplate;

@Autowired
public void setDataSource(DataSource dataSource) {
    this.namedParameterJdbcTemplate = new NamedParameterJdbcTemplate(dataSource);
}

final List<Long> resultList = namedParameterJdbcTemplate.query(query, 
            mapOfNamedParamters, 
            new RowMapper<Long>() {
        @Override
        public Long mapRow(ResultSet rs, int rowNum) throws SQLException {
            return rs.getLong(1);
        }
    });
5
lekant

Utilisez set Parameter from query.

Query q = (Query) em.createNativeQuery("SELECT count(*) FROM mytable where username = ?1");
q.setParameter(1, "test");
4
pL4Gu33