157

I have built a NamedQuery that looks like this:

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

What I want to do is fill in the parameter :inclList with a list of items instead of one item. For example if I have a new List<String>() { "a", "b", "c" } how do I get that in the :inclList parameter? It only lets me codify one string. For example:

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

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

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

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

I know I could just build a string and build the whole Query from that, but I wanted to avoid the overhead. Is there a better way of doing this?

Related question: if the List is very large, is there any good way of building query like that?

AlanObject
  • 9,613
  • 19
  • 86
  • 142
  • This is a duplicate of https://stackoverflow.com/questions/1557085/setting-a-parameter-as-a-list-for-an-in-expression#7967570 but this thread provides useful answers. – Mike Ryan Jul 27 '18 at 20:26

4 Answers4

218

When using IN with a collection-valued parameter you don't need (...):

@NamedQuery(name = "EventLog.viewDatesInclude", 
    query = "SELECT el FROM EventLog el WHERE el.timeMark >= :dateFrom AND " 
    + "el.timeMark <= :dateTo AND " 
    + "el.name IN :inclList") 
axtavt
  • 239,438
  • 41
  • 511
  • 482
  • 9
    Nope ... I my case its opposite. If I use :inclList then its not working. If I use IN (:inclList) then it works. – Gunjan Shah Nov 24 '12 at 10:27
  • 2
    Also note mentioning: the type of your param has to be an collection (not an array) of objects. The objects must match the type of the field. .toString() is no substitute for class String – dube Mar 21 '14 at 10:47
  • 2
    I think this is something that has changed with the versions of Hibernate, as far as I can remember I have gotten an error when not having the paranthesis around the variable when using IN. Strange if it's not backwards compatible.. – Tobb Aug 13 '14 at 14:10
  • 1
    This was indeed an hibernate bug (the need of parenthesis) that's been fixed in 3.6.1 – Mat Mar 11 '16 at 09:00
  • 2
    For related question: In case of very large list there could be limitations for the in implementation. E.g. oracle 11g. max. 1000 list elements as parameter are possible. A workaround is to chop the list in subLists and collect the results. JPA itself does not restrict the list size. – Mahttias Schrebiér Oct 25 '16 at 08:00
  • It did work. Thanks for that. Now, how do I make this an optional filter? `:inclList IS NULL OR el.name IN : inclList` throws `QuerySyntaxException: unexpected AST node` because it concatenates the whole list in the first part as well. – Guilherme Taffarel Bergamin Aug 13 '21 at 17:45
102

The proper JPA query format would be:

el.name IN :inclList

If you're using an older version of Hibernate as your provider you have to write:

el.name IN (:inclList)

but that is a bug (HHH-5126) (EDIT: which has been resolved by now).

wolφi
  • 8,091
  • 2
  • 35
  • 64
Jose Ferrer
  • 1,188
  • 1
  • 7
  • 9
37
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();
    }

Works for me with JPA 2, Jboss 7.0.2

Mark Hall
  • 53,938
  • 9
  • 94
  • 111
user1114134
  • 598
  • 1
  • 6
  • 10
21

You should convert to List as shown below:

    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
  • 311
  • 2
  • 4