Mapeamento Objeto-Relacional em Java usando Oracle Toplink: Parte 3
A JPQL também é uma especificação da JPA. É uma linguagem, semelhante à SQL. Diferente da SQL que trabalha com tabelas, a JPQL trabalha com entidades (classes).
Selecionando todos os objetos de uma entidade
As queries são criadas e executadas com o auxílio da classe EntityManager, usando o método createQuery. Existem outros dois métodos semelhantes: createNativeQuery e createNamedQuery. O primeiro é para usar queries escritas em SQL puro (nativas), o segundo veremos mais adiante.
Crie uma classe chamada SelectAll, o código dela fica assim: http://pastebin.com/f3aa9d3bc. Esteja atento a duas coisas:
- Não tem SELECT *;
- Você deve importar a interface Query do pacote javax.persistence.
O código mostrado é muito simples. Vamos agora começar a filtrar resultados e ver como os joins não são tão complicados aqui :)
Filtrando resultados
Vamos fazer apenas uma filtragem simples. Note que a JPQL é muito semelhante à SQL. Vamos selecionar todos os status que começam com a letra V. Você pode pensar: “em SQL eu uso o like, o que será que eu uso na JPQL?”. O like também! Veja o código:
List<Status> status = query.getResultList();
for(Status s : status){
System.out.println(s.getNome());
}
Nada demais, quase igual à SQL. O nome dos atributos deve ser equivalente ao nome dado nas classes. Esqueça as tabelas no banco de dados, você não vai usar nada de lá :) Não explicitamente.
JOIN’s
Uma das coisas mais legais em trabalhar com banco de dados relacionais é fazer JOIN. O problema é que os joins costumam gerar consultar enormes. Vamos fazer a seguinte consulta: Eu quero obter todos os clientes que compraram um produto cujo nome (do produto, caso haja ambiguidade aqui) começa com a letra A. :) Como a JPQL é muito semelhante à SQL, vamos fazer assim ué:
WHERE ic.compra = c AND c.cliente = p AND ic.produto = p AND p.nome LIKE 'A%'
Taí, um SELECT pra ninguém botar defeito. Na verdade, eu boto defeito. A JPQL não seria tão útil se não pudesse melhorar a forma de fazer consultas no banco de dados. É nesse momento que as pessoas têm mais problemas com SQL :) Vamos reescrever a query?
Melhorou? Pois é, o Toplink processa essa query e gera algo semelhante à query anterior. Mas para o programador é mais fácil não usar tantos joins. Nós declaramos estar selecionando dados somente de uma entidade, mas por baixo dos panos é feita uma consulta que acessa quatro tabelas. Isso sim é VHPL :)
Bind variable
Já aprendemos a usar as queries. Mas uma coisa muito importante que encontramos no JDBC e ainda não vimos na JPA é a possibilidade de fornecer parâmetros às queries.
Diferente de como acontece no JDBC, na JPA os parâmetros possuem nome e não número. Em JDBC declaramos os parâmetros usando pontos de exclamação (“?”) e configuramos estes parâmetros usando seu número. Na JPA, os parâmetros têm nome:
O nome do parâmetro é “nome”. Todo parâmetro é identificado pelos dois pontos (“:”) seguidos do nome do parâmetro. Vamos agora ver um código onde setamos o parâmetro:
query.setParameter("nome", "Vivo");
List<Status> status = query.getResultList();
for(Status s : status) {
System.out.println(s.getNome());
}
Obs: Se você quiser, pode configurar todos os parâmetros usando números também.
Dando nome às queries
Bom, já vimos como criar queries, já vimos como filtrar resultados, como fazer join’s e como adicionar parâmetros a uma query. Um recurso interessante é deixar a query pronta, e depois chamar ela pelo nome. :)
Você cria uma NamedQuery na entidade e depois acessa ela pelo nome. Legal né?! Vamos ver como fazer isso. Abra a classe Status e adicione abaixo da linha @Entity as seguintes linhas:
@NamedQuery(name = "SelecionarTodosStatus",
query = "SELECT s FROM Status s"),
@NamedQuery(name = "SelecionarStatusPeloNome",
query = "SELECT s FROM Status s WHERE s.nome = :nome")
})
Entendeu o que fizemos? Criamos uma query chamada SelecionarTodosStatus e outra criada SelecionarStatusPeloNome. Agora vamos usá-la. Crie a classe SelectNamedQuery, com o seguinte código: http://pastebin.com/f65f464b8.
Ao invés de usarmos o createQuery, usamos o createNamedQuery. Passamos o nome da Query, o Toplink encontra ela, processamos os parâmetros (se existirem) e pronto, temos o resultado! :)
Na próxima, e última, parte vou apresentar uma ideia nova para criação de classes Dao, usando o recurso de tipagem genérica do Java. Não é algo ligado ao Toplink ou à JPA. Vou mostrar o modelo de criação das classes Dao, e exemplificar como eu faria usando Toplink (mostrando como é fácil) e JDBC (vai dar mais trabalho).


Caro Francisco.
Por um acaso não está faltando um import para a classe Status?
Digo isso por causa da linha 17:
List<-S-t-a-t-u-s> todos = queryTodos.getResultList();
Aqui pediu um import, mas mesmo importanto não rodou…
O erro retornado foi o seguinte:
Exception in thread "main" java.lang.IllegalArgumentException: NamedQuery of name: SelecionarTodosStatus not found.
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.getDatabaseQuery(EJBQueryImpl.java:422)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.setAsSQLReadQuery(EJBQueryImpl.java:136)
at oracle.toplink.essentials.internal.ejb.cmp3.base.EJBQueryImpl.getResultList(EJBQueryImpl.java:464)
at db.SelectNamedQuery.main(SelectNamedQuery.java:18)
Java Result: 1
Estou me referindo a classe que vc. disponibilizou no endereço:
http://pastebin.com/f65f464b8
por sinal achei estranho o pacote aonde a classe está.
Um grande abraço e até mais!!!
ps.
escrevi -S-t-a-t-u-s pq o esta é uma palavra reservada do sistema de comentários!
Salve Leonam! :D
Basta adicionar o import mesmo, mas tem que ficar esperto pra importar a classe correta, por que na API do Java existem algumas classes que se chamam Status.
Mas o erro que você me passou indica que o EntityManager não ta encontrando a query "SelecionarTodosStatus". Você adicionou ela na classe Status? Sua classe Status está assim: http://is.gd/1QsmT?
Abraços! ;)
Olá Francisco!
Obrigado pelo seu breve retorno, o meu problema foi solucionado, realmente o EntityManager não estava encontrando.
De toda forma, hoje usei aquela classe que estava naquele link, dei um build e tudo funcionou corretamente.
A classe estava no EntityManager mas de alguma forma realmente não estava encontrando, dei um re-build e funcionou!
Obrigado!!!
Tudo Bem Francisco! D+ seu exclarecimento…achei muito bom e é dificil achar um material tão completo sobre o toplink com jpa e query como você mostrou…
Eu estou tendo um problema que talvez com sua experiencia você já deve ter passado:
Eu tenho um relacionamento muitos para zero, que é significa muitos para um ou zero, mas quando efetuo o cadastro com o valor null na chave estrangeira e tento fazer um select do registro ele não me traz o registro que tem o campo null.
preciso muito resolver isso…
obrigado.
Meu e-mail é adalton@dri.cefetmg.br
[...] Parte 3: Usando a JPQL (Java Persistence Query Language); [...]