CriteriaQuery - Como fazer o where?

Bom dia Galera!

Fiz um programinha seguindo um vídeo do youtube, que usa templates do Netbeans e JSF.
o vídeo http://www.youtube.com/watch?v=9LoBI79rzGI

Ele cria um método

    public List<T> findAll() {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

Que lista todos registros, porém, eu gostaria de criar outro método que fizesse assim:

    public List<T> findByName(String nome) {
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        //Aqui é a zebra...
        //cq.select(cq.where("nome like '%"+nome+"%'"));
        //sei que não é assim não dá.
        return getEntityManager().createQuery(cq).getResultList();
    }

Como eu posso implementar esse meu where ?
Estou usando JPA e EclipseLink.

Obrigado e um grande abraço

DRauber

Pesquise sobre a classe Restriction

criteria.add(Restrictions.ilike("nome", "%parametro%"));

Referência: http://docs.jboss.org/hibernate/core/3.3/reference/en/html/querycriteria.html

Ops :shock:
Achei que vc estava usando hibernate.

Supondo q vc tenha em seu projeto uma entidade Person:

public class PersonDAO {

  @Inject EntityManager em;

  public List<Person> findByName(String name) {
    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<Person> cq = cb.createQuery(Person.class);
    Root<Person> f = cq.from(Person.class);
    cq.where(cb.like(f.get(Person_.nome, "%" + name + "%")));
    return em.createQuery(cq).getResultList();
  }

}

Lembre-se tb de adicionar o metamodel Person_ no mesmo pacote de Person.

@StaticMetamodel(Person.class)
public class Person_ {

  public static volatile SingularAttribute<Person, Long> id;
  public static volatile SingularAttribute<Person, String> name;
  // adicione os demais atributos de Person tb.

}

Da p/ vc ver q o código é bastante volumoso de maneira q é preferível q vc use NamedQueries. NamedQueries são mais simples e dispensam o padrão DAO, ou seja, é um artefato a menos p/ vc gerar quando estiver programando. Use CriteriaQueries apenas quando vc precisar criar queries dinâmicamente, tipo, quando vc tiver um formulário como aquele formulário de busca avançada do google com um montão de campos e vc precisar montar uma busca com apenas os campos preenchidos pelo usuário. O uso de CriteriaQueries viola o princípio KISS.

[quote=dev.rafael]

Da p/ vc ver q o código é bastante volumoso de maneira q é preferível q vc use NamedQueries. NamedQueries são mais simples e dispensam o padrão DAO, ou seja, é um artefato a menos p/ vc gerar quando estiver programando. Use CriteriaQueries apenas quando vc precisar criar queries dinâmicamente, tipo, quando vc tiver um formulário como aquele formulário de busca avançada do google com um montão de campos e vc precisar montar uma busca com apenas os campos preenchidos pelo usuário. O uso de CriteriaQueries viola o princípio KISS.[/quote]

Poxa, eu achei que tava muito complicado mesmo…

To tentando usar NamedQueries…
Na classe contato, criei a anotação

@NamedQueries(@NamedQuery(name="bean.findByNAme",query="select c.* from contato c where c.nome like :nome"))

Alterei o meu método para:

    public List<T> findByName(String nome) {
        Query query= getEntityManager().createNamedQuery("bean.findByName");
        nome = "%"+nome+"%";
        query.setParameter("nome",nome);
        return query.getResultList();
    }

porém, estou recendo o erro:
Caused by: Exception [EclipseLink-8025] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing the query [bean.findByNAme: select c.* from contato c where c.nome like :nome], line 1, column 9: unexpected token [*].

Escrevi o select como seria no banco… Tá errado ? Como é o certo?

Obrigado…

DRauber

O problema da sua query é o “*”. Tente assim:

@NamedQueries({
  @NamedQuery(name = Bean.BY_NAME, query = "select c from contato c where c.nome like :nome")
})
public class Bean {
  public static final String BY_NAME = "Bean.byName";
}

Como no código assim, prefira constantes ao invés de strings literais p/ nomes de suas namedqueries. Outra coisa, não crie DAOs. Com as namedqueries o EntityManager ganha um interface de DAO genérico.

@Named
public class BeanController {

  @Inject EntityManager em;

  private String name;

  public String getName() { return name; }
  public void setName(String name) { this.name = name; }

  public List<Bean> getBeans() {
    return em.createNamedQuery(Bean.BY_NAME, Bean.class)
                  .setParameter("name", name)
                  .getResultList();
  }

}

Criar uma classe dedicada a execução de NamedQueries é um tanto quando overengineering.

Obrigado dev.rafael!

Não entendi muito bem :oops:
Eu devo criar uma Classe Bean e colocar todas NamedQueryes nela ?
Devo também criar uma Classe BeanController para fazer a chamada à classe Bean ?

Mesmo sem entender direito, consegui fazer o código anterior funcionar. O meu erro estava no “*” e no “from contato”, quando deveria ser “from Contato”.

Mais uma dúvida no mesmo assunto… coloquei o comando “like”, mas eu gostaria de usar o ilike do postgresql, para não considerar case sensitive. Tem como ?

Vlw

DRauber

Não! O JPA não suporta nada como o ILIKE. O q vc pode fazer é:

lower(b.name) like lower(%dev%)

[quote=dev.rafael]Não! O JPA não suporta nada como o ILIKE. O q vc pode fazer é:

lower(b.name) like lower(%dev%) [/quote]

Num dá… eu tinha tentado com upper, agora tentei com o lower…
e o erro reportado

Caused by: Exception [EclipseLink-8025] (Eclipse Persistence Services - 2.0.1.v20100213-r6600): org.eclipse.persistence.exceptions.JPQLException
Exception Description: Syntax error parsing the query [bean.findByName: select c from Contato c where lower(c.nome) like lower(:nome)], line 1, column 49: unexpected token [lower].

Vlw

DRauber

Então o seu provider deve estar bugado. Pq tanto “lower” quanto “upper” fazem parte da jpql desde a especificação 1.0.
http://download.oracle.com/javaee/5/tutorial/doc/bnbuf.html#bnbui

Estranho…

assim @NamedQuery(name=“bean.findByName”,query=“select c from Contato c where UPPER(c.nome) like :nome”))
funciona… fiz o parametro passado para a função ser modificado também, aí deu certo.

Obrigado!

DRauber