web-dev-qa-db-fra.com

Faire une requête "IN" avec Hibernate

J'ai une liste d'identifiants dans une chaîne et je veux utiliser Hibernate pour obtenir les lignes avec ces identifiants. TrackedItem est une entité Hibernate/JPA (désolé si les noms que je vous donne sont mélangés ici).

Mon code est:

String idsText = "380, 382, 386";
ArrayList<Long> ids = new ArrayList<Long>();

for (String i : idsText.split(","))
{
    ids.add(Long.getLong(i));
}

List<TrackedItem> items = TrackedItem.find("id IN (?)", ids).fetch();

Mais cela échoue: JPAQueryException occured : Error while executing query from models.TrackedItem where id IN (?): Java.util.ArrayList cannot be cast to Java.lang.Long

Comment puis-je faire fonctionner la partie IN? Merci.

31
Amy B

La syntaxe de votre requête JPQL est incorrecte. Soit utiliser (avec un paramètre de position):

List<Long> ids = Arrays.asList(380L, 382L, 386L);
Query query = em.createQuery("FROM TrackedItem item WHERE item.id IN (?1)");
query.setParameterList(1, ids)
List<TrackedItem> items = query.getResultList();

Ou (avec un paramètre nommé):

List<Long> ids = Arrays.asList(380L, 382L, 386L);
Query query = em.createQuery("FROM TrackedItem item WHERE item.id IN :ids");
query.setParameterList("ids", ids)
List<TrackedItem> items = query.getResultList();

Ci-dessous, les sections pertinentes de la spécification JPA 1.0 concernant les paramètres:

4.6.4.1 Paramètres de position

Les règles suivantes s'appliquent aux paramètres de position.

  • Les paramètres d'entrée sont désignés par le préfixe du point d'interrogation (?) Suivi d'un entier. Par exemple: ?1.
  • Les paramètres d’entrée sont numérotés à partir de 1.
    Notez que le même paramètre peut être utilisé plusieurs fois dans la chaîne de requête et que l'ordre d'utilisation des paramètres dans la chaîne de requête n'a pas besoin d'être conforme à l'ordre des paramètres de position.

4.6.4.2 Paramètres nommés

Un paramètre nommé est un identifiant préfixé par le symbole ":". Il suit les règles pour les identifiants définis dans la section 4.4.1. Les paramètres nommés sont sensibles à la casse.

Exemple:

SELECT c
FROM Customer c
WHERE c.status = :stat

La section 3.6.1 décrit l'API pour la liaison de paramètres de requête nommés.

58
Pascal Thivent

Si vous avez la malchance d'utiliser une veille prolongée non-JPA, vous devriez utiliser ceci:

Query query = session.createQuery("FROM TrackedItem item WHERE item.id IN (:items)");
query.setParameterList("items", Arrays.asList(380L, 382L, 386L));

@SuppressWarnings("unchecked")
List<TrackedItem> results = query.list();
10
depsypher

Même lorsque votre requête s'exécute correctement, vous pouvez faire face à une erreur si votre paramètre de requête contient trop de valeurs. 

Une solution possible à ce problème, si vous utilisez Hibernate 5.1 ou une version plus récente, consiste à utiliser Session.byMultipleIds ().

session
    .byMultipleIds(TrackedItem.class)
    .multiLoad(1L, 2L, 3L);

Pour plus d'informations, voir https:// Thoughts-on-Java.org/fetch-multiple-entities-id-hibernate/

0
Aleksandar Radulović