Cláusula JPQL IN: Java-Arrays (ou Listas, Conjuntos ...)?

108

Gostaria de carregar todos os objetos que têm uma tag textual definida para qualquer um de um número pequeno, mas arbitrário de valores de nosso banco de dados. A maneira lógica de fazer isso no SQL seria construir uma cláusula "IN". JPQL permite IN, mas parece exigir que eu especifique cada parâmetro para IN diretamente (como em, "in (: in1,: in2,: in3)").

Existe alguma maneira de especificar uma matriz ou lista (ou algum outro contêiner) que deve ser desenrolada para os valores de uma cláusula IN?

Bernd Haug
fonte

Respostas:

208

Não tenho certeza para JPA 1.0, mas você pode passar um Collectionem JPA 2.0:

String qlString = "select item from Item item where item.name IN :names"; 
Query q = em.createQuery(qlString, Item.class);

List<String> names = Arrays.asList("foo", "bar");

q.setParameter("names", names);
List<Item> actual = q.getResultList();

assertNotNull(actual);
assertEquals(2, actual.size());

Testado com EclipseLInk. Com o Hibernate 3.5.1, você precisará colocar o parâmetro entre parênteses:

String qlString = "select item from Item item where item.name IN (:names)";

Mas isso é um bug, a consulta JPQL na amostra anterior é JPQL válida. Consulte HHH-5126 .

Pascal Thivent
fonte
5
há um número máximo de nomes a serem usados ​​em "na cláusula"?
Gondim
3
O bug mencionado no Hibernate parece ter sido corrigido na versão 3.6.1
Denis Kniazhev
1
@pringlesinn o número de valores em uma cláusula IN depende do seu DBMS
Tim Büthe
funciona em JPA 1.0 (e não é obrigatório entre parênteses, mas para facilitar a leitura, você deve)
Javier Larios
e se você quiser => item.name em (como: nomes)
dzgeek
3

O limite do oráculo é de 1000 parâmetros. O problema foi resolvido pelo hibernate na versão 4.1.7 embora dividindo a lista de parâmetros passada em conjuntos de 500 veja JIRA HHH-1123

Ashish Thukral
fonte
1
Infelizmente, isso não foi resolvido. O tíquete foi marcado como resolvido, mas o problema (conforme mostrado pelos comentários) não foi corrigido pela equipe do Hibernate.
Druckles
@Druckles um onde? Não vejo comentários anteriores a 2016. E esses eram apenas dois comentários que não diziam praticamente nada além do usual 'socorro! 11 !!!!' da internet. Você não deu motivos para confiar que o relatório de bug foi resolvido.
searchengine27
@ searchengine27 Disse que o relatório não foi resolvido, apesar de ter sido marcado como resolvido. A resolução foi, conforme relatado por Steve Ebersole: "A solução para isso é que vamos simplesmente avisar os usuários por meio de registro quando essa condição for detectada." Os comentários de Noel Trout em 2012 explicam por que isso não é suficiente.
Druckles
Em outras palavras, essa resposta está errada ou, na melhor das hipóteses, enganosa.
Druckles