Dodawanie listy klauzul IN do zapytania JPA

125

Zbudowałem NamedQuery, które wygląda następująco:

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

To, co chcę zrobić, to wypełnić parametr: includeList listą pozycji zamiast jednej pozycji. Na przykład, jeśli mam, new List<String>() { "a", "b", "c" }jak mogę to uzyskać w parametrze: inclList? Pozwala mi tylko skodyfikować jeden ciąg. Na przykład:

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

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

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

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

Wiem, że mógłbym po prostu zbudować ciąg znaków i na jego podstawie zbudować całe zapytanie, ale chciałem uniknąć narzutu. Czy jest lepszy sposób na zrobienie tego?

Powiązane pytanie: jeśli lista jest bardzo duża, czy istnieje dobry sposób na zbudowanie takiego zapytania?

AlanObject
źródło
To jest duplikat stackoverflow.com/questions/1557085/ ... ale ten wątek zawiera przydatne odpowiedzi.
Mike Ryan

Odpowiedzi:

182

W przypadku używania INz parametrem o wartości kolekcji nie potrzebujesz (...):

@NamedQuery(name = "EventLog.viewDatesInclude", 
    query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND " 
    + "el.timeMark <= :dateTo AND " 
    + "el.name IN :inclList") 
axtavt
źródło
6
Nie ... W moim przypadku jest odwrotnie. Jeśli używam: incList, to nie działa. Jeśli używam IN (: incList), to działa.
Gunjan Shah
1
Zwróć też uwagę na to, że typ parametru musi być zbiorem (nie tablicą) obiektów. Obiekty muszą pasować do typu pola. .toString () nie zastępuje klasy String
dube
2
Myślę, że jest to coś, co zmieniło się wraz z wersjami Hibernate, o ile pamiętam, otrzymałem błąd, gdy nie miałem parantezy wokół zmiennej podczas używania IN. Dziwne, jeśli nie jest kompatybilne wstecz ...
Tobb
1
To rzeczywiście był błąd hibernacji (potrzeba nawiasów), który został naprawiony w 3.6.1
Mat
1
W przypadku pytania pokrewnego: W przypadku bardzo dużej listy mogą wystąpić ograniczenia dotyczące implementacji. Np. Wyrocznia 11g. max. Możliwych jest 1000 elementów listy jako parametr. Rozwiązaniem jest podzielenie listy na subLists i zebranie wyników. Sam JPA nie ogranicza rozmiaru listy.
Mahttias Schrebiér
81

Właściwy format zapytania JPA to:

el.name IN :inclList

Jeśli jako dostawca używasz starszej wersji Hibernate, musisz napisać:

el.name IN (:inclList)

ale to jest błąd ( HHH-5126 ) (EDYCJA: który został już rozwiązany).

Jose Ferrer
źródło
5
Dziękujemy za wyróżnienie starszych wersji 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();
    }

Działa dla mnie z JPA 2, Jboss 7.0.2

user1114134
źródło
9

Musisz przekonwertować na, Listjak pokazano poniżej:

    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
źródło
Dzięki tej odpowiedzi pomogła mi
cabaji99