Ajout d'une liste de clauses IN à une requête JPA

125

J'ai construit un NamedQuery qui ressemble à ceci:

@NamedQuery(name = "EventLog.viewDatesInclude",
        query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND "
        + "el.timeMark <= :dateTo AND "
        + "el.name IN (:inclList)")

Ce que je veux faire, c'est remplir le paramètre: inclList avec une liste d'éléments au lieu d'un élément. Par exemple, si j'ai un new List<String>() { "a", "b", "c" }comment puis-je obtenir cela dans le paramètre: inclList? Cela ne me permet de codifier qu'une seule chaîne. Par exemple:

setParameter("inclList", "a") // works

setParameter("inclList", "a, b") // does not work

setParameter("inclList", "'a', 'b'") // does not work

setParameter("inclList", list) // throws an exception

Je sais que je pourrais simplement créer une chaîne et construire toute la requête à partir de cela, mais je voulais éviter la surcharge. Existe-t-il une meilleure façon de le faire?

Question connexe: si la liste est très grande, existe-t-il un bon moyen de créer une requête comme celle-ci?

AlanObject
la source
Ceci est un double de stackoverflow.com/questions/1557085/… mais ce fil fournit des réponses utiles.
Mike Ryan

Réponses:

182

Lors de l'utilisation INavec un paramètre à valeur de collection, vous n'avez pas besoin (...):

@NamedQuery(name = "EventLog.viewDatesInclude", 
    query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND " 
    + "el.timeMark <= :dateTo AND " 
    + "el.name IN :inclList") 
axtavt
la source
6
Non ... je mon cas son contraire. Si j'utilise: inclList, cela ne fonctionne pas. Si j'utilise IN (: inclList), cela fonctionne.
Gunjan Shah
1
Notez également que le type de votre paramètre doit être une collection (pas un tableau) d'objets. Les objets doivent correspondre au type du champ. .toString () ne remplace pas la classe String
dube
2
Je pense que c'est quelque chose qui a changé avec les versions d'Hibernate, pour autant que je me souvienne, j'ai eu une erreur lorsque je n'ai pas de paranthèse autour de la variable lors de l'utilisation de IN. Étrange si ce n'est pas rétrocompatible ..
Tobb
1
Il s'agissait en effet d'un bogue de mise en veille prolongée (le besoin de parenthèses) qui a été corrigé dans la version 3.6.1
Mat
1
Pour une question connexe: En cas de liste très longue, il pourrait y avoir des limitations pour la mise en œuvre. Par exemple, oracle 11g. max. 1000 éléments de liste en tant que paramètre sont possibles. Une solution de contournement consiste à découper la liste en sous-listes et à collecter les résultats. JPA lui-même ne limite pas la taille de la liste.
Mahttias Schrebiér
81

Le format de requête JPA approprié serait:

el.name IN :inclList

Si vous utilisez une ancienne version d'Hibernate comme fournisseur, vous devez écrire:

el.name IN (:inclList)

mais c'est un bug ( HHH-5126 ) (EDIT: qui a été résolu maintenant).

José Ferrer
la source
5
Merci d'avoir distingué les anciennes versions d'Hibernate use ()
Rob L
32
public List<DealInfo> getDealInfos(List<String> dealIds) {
        String queryStr = "SELECT NEW com.admin.entity.DealInfo(deal.url, deal.url, deal.url, deal.url, deal.price, deal.value) " + "FROM Deal AS deal where deal.id in :inclList";
        TypedQuery<DealInfo> query = em.createQuery(queryStr, DealInfo.class);
        query.setParameter("inclList", dealIds);
        return query.getResultList();
    }

Fonctionne pour moi avec JPA 2, Jboss 7.0.2

user1114134
la source
9

Vous devez convertir Listcomme indiqué ci-dessous:

    String[] valores = hierarquia.split(".");       
    List<String> lista =  Arrays.asList(valores);

    String jpqlQuery = "SELECT a " +
            "FROM AcessoScr a " +
            "WHERE a.scr IN :param ";

    Query query = getEntityManager().createQuery(jpqlQuery, AcessoScr.class);                   
    query.setParameter("param", lista);     
    List<AcessoScr> acessos = query.getResultList();
Wesley Rocha
la source
Thx cette réponse m'a aidé
cabaji99