Parâmetro na cláusula semelhante JPQL

90

Estou tentando escrever uma consulta JPQL com uma cláusula like:

LIKE '%:code%'

Eu gostaria de ter code = 4 e encontrar

455
554
646
...

Eu não posso passar :code = '%value%'

namedQuery.setParameter("%" + this.value + "%");

porque em outro lugar não preciso :valueembrulhado pelos %chars. Qualquer ajuda?

Manuel Drieschmanns
fonte
2
@Manuele Piastra: A resposta abaixo não é o que você procurava?
wmorrison365

Respostas:

169

Se você fizer

LIKE :code

e então faça

namedQuery.setParameter("code", "%" + this.value + "%");

Então o valor permanece livre do sinal '%'. Se você precisar usá-lo em outro lugar na mesma consulta, simplesmente use outro nome de parâmetro diferente de 'código'.

comandante do navio
fonte
9
Para registro, isso não o deixa vulnerável a ataques de injeção de JPQL porque this.value é automaticamente escapado de maneira adequada para você.
László van den Hoek,
3
Isso "%" + this.value + "%"é o que escapou.
Gustavo
2
Como faço para que não faça distinção entre maiúsculas e minúsculas?
EM-Creations,
55

Eu não uso parâmetros nomeados para todas as consultas. Por exemplo, é incomum usar parâmetros nomeados em JpaRepository .

Para contornar o problema, uso a função JPQL CONCAT (este emulador de código começa com ):

@Repository
public interface BranchRepository extends JpaRepository<Branch, String> {
    private static final String QUERY = "select b from Branch b"
       + " left join b.filial f"
       + " where f.id = ?1 and b.id like CONCAT(?2, '%')";
    @Query(QUERY)
    List<Branch> findByFilialAndBranchLike(String filialId, String branchCode);
}

Encontrei essa técnica em documentos excelentes: http://openjpa.apache.org/builds/1.0.1/apache-openjpa-1.0.1/docs/manual/jpa_overview_query.html

Gavenkoa
fonte
2
Nota: CONCAT (? 2, '%') adicionará '%' ao final do parâmetro, use CONCAT ('%',? 2, '%') para adicioná-lo ao início e ao final do parâmetro.
Muizz Mahdy de
7

Você pode usar a função JPA LOCATE .

LOCATE (searchString, candidateString [, startIndex]) : Retorna o primeiro índice de searchString em candidateString. As posições são baseadas em 1. Se a string não for encontrada, retorna 0.

Para sua informação: a documentação do meu principal hit do Google teve os parâmetros invertidos.

SELECT 
  e
FROM 
  entity e
WHERE
  (0 < LOCATE(:searchStr, e.property))
David Carlson
fonte
1
para mim, a melhor solução - sem concatenação, sem injeção de SQL.
hgoebl
4

Não sei se estou atrasado ou fora do escopo, mas na minha opinião eu poderia fazer assim:

String orgName = "anyParamValue";

Query q = em.createQuery("Select O from Organization O where O.orgName LIKE '%:orgName%'");

q.setParameter("orgName", orgName);
Ishimwe Aubain Consolateur
fonte
2

Existe um bom método like () na API de critérios JPA. Tente usar isso, espero que ajude.

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery criteriaQuery = cb.createQuery(Employees.class);
Root<Employees> rootOfQuery = criteriaQuery.from(Employees.class);
criteriaQuery.select(rootOfQuery).where(cb.like(rootOfQuery.get("firstName"), "H%"));
Haroon
fonte
1
  1. Use a consulta JPQL abaixo.
select i from Instructor i where i.address LIKE CONCAT('%',:address ,'%')");
  1. Use o código de critérios abaixo para o mesmo:
@Test
public void findAllHavingAddressLike() {
    CriteriaBuilder cb = criteriaUtils.criteriaBuilder();
    CriteriaQuery<Instructor> cq = cb.createQuery(Instructor.class);
    Root<Instructor> root = cq.from(Instructor.class);
    printResultList(cq.select(root).where(
        cb.like(root.get(Instructor_.address), "%#1074%")));
}
Vaneet Kataria
fonte
0

Apenas deixe de fora o ''

LIKE %:code%
Sehtim
fonte
Downvote: não está funcionando, isso muda o nome do parâmetro para o código%
kaiser
0

Use JpaRepositoryou CrudRepositorycomo interface de repositório:

@Repository
public interface CustomerRepository extends JpaRepository<Customer, Integer> {

    @Query("SELECT t from Customer t where LOWER(t.name) LIKE %:name%")
    public List<Customer> findByName(@Param("name") String name);

}


@Service(value="customerService")
public class CustomerServiceImpl implements CustomerService {

    private CustomerRepository customerRepository;
    
    //...

    @Override
    public List<Customer> pattern(String text) throws Exception {
        return customerRepository.findByName(text.toLowerCase());
    }
}
KarishmaP
fonte