3
respostas

Query com parâmetros dinâmicos.

Minha dúvida é quanto ao JPA Hibernate.

Não é possível fazer uma query com parâmetros dinâmicos de forma simples sem ter que usar Criteria?

Por exemplo:

Tenho uma query dentro do meu repository:

public String findByNameAndAdressAndPhone (String name,String Adress, String Phone);

Automaticamente o CrudRepository sabe que o Name é um campo da minha entity ou tabela assim como o Adress e Phone e também sabe que os And são os and para montar o select. Ele até sugestiona pressionando o control espaço. Mas existe um problema grave ai... Caso um dos parâmetros passados vier vazio, ou seja, o usuario na tela de pesquisa resolveu usar somente como filtro o nome (Name), o select vai retornar nulo pq ele vai procurar um cara com nome de fulano na tabela, vai encontrar mas não com endereço e telefone vazio, entendem? Exite uma forma simples de falar ali mesmo no select "Olha esses parâmetros podem ser nulos"?

Por exemplo uma anotação:

Eu encontrei isso, será que funciona?

public enum NullBehavior {
    EQUALS, IS, IGNORED
}

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.PARAMETER})
public @interface NullMeans {
    NullBehavior value() default NullBehavior.EQUALS;
}


public interface FooRepository extends JpaRepository<Foo> {

  List<Foo> findByBarAndGoo(@NullMeans(IGNORED) Bar bar, @NullMeans(IGNORED) Goo goo);
}


public interface FooRepository extends JpaRepository<Foo> {

  List<Foo> findByBarAndGoo(@NullMeans(IGNORED) Bar bar, @NullMeans(IGNORED) Goo goo);
}

public interface BlazRepository extends JpaRepository<Blaz> {

  @NullMeans(IGNORED) // applies to all parameters unless overriden by @NullMeans on parameter(s)
  List<Blaz> findByFooAndGooAndHooAndKooAndLoo(Foo foo, Goo goo, Hoo hoo, Koo koo, @NullMeans(IS) Loo loo);
}

Link dos idos onde encontrei o código:

https://jira.spring.io/si/jira.issueviews:issue-html/DATAJPA-209/DATAJPA-209.html

Alguém tem alguma solução prática no próprio JPA, sem usar Query e etc... Não é possível que fizeram isso com um poderoso framework. Uma coisa tão comum de se usar e não ter uma anotação simples dizendo que o parametro pode ser ignorado caso venha nulo.

Obrigado!

3 respostas

Oi Lars,

dá uma olhada no recurso "Query by Example" especifico do Hibernate:

http://blog.caelum.com.br/simplifique-suas-consultas-com-o-query-by-example-do-hibernate/

abs, Nico

Nico obrigado pela resposta. Foi mais ou menos o que eu fiz antes de sua resposta, porém não usei o criteria. Usei entitymanager e Stringbuilder pra criar a query dependendo dos parâmetros.

Quanto a questão de performance, será a mesma de usar o criteria?

Obrigado!

Oi Lars,

Não sei eu entendi :) mas a ideia é não usar o StringBuilder. No artigo do blog, lá no final, tem um exemplo chamada "Query by Example" que vc poderia aplicar para resolver o seu problema:

Example example = Example.create(restaurante);
List<Restaurante> restaurantes = s.createCriteria(Restaurante.class)
    .add(example).list(); 

Um objeto entidade serve como exemplo para gerar o SQL. Ou seja, dependendo como vc preenche esse objeto será gerado dinâmicamente o SQL. Tudo bem?

Da performance, não deve ter diferença, no final é um SQL a executar (é muito mais importante ver o desempenho do SQL em si do que da geração dele).

abs, Nico