Beruflich Dokumente
Kultur Dokumente
Vamos continuar com o projeto finanas. J vimos como montar consultas usando o JPQL. Era preciso abrir um EntityManager para criar uma Query e definir a consulta atravs do JPQL. Com a Query em mos, preenchemos os parmetros e a executamos com o mtodo getResultList():
EntityManager manager = new JPAUtil().getEntityManager(); Query query = manager.createQuery( "select m from Movimentacao m" + "where m.conta.id=:pId" +" and m.tipoMovimentacao = :pTipo" +" order by m.valor desc"); query.setParameter("pId", 3); query.setParameter("pTipo", TipoMovimentacao.ENTRADA); List<Movimentacao> movimentacoes = query.getResultList();
String jpql = "select m from Movimentacao m where m.conta=:pConta " + "and m.tipoMovimentacao=:pTipo";
Mas
dessa
maneira
estaramos
retornando
lista
com
todas
as
movimentaes, e no bem isso que queremos. Queremos apenas a soma dos valores e, para isso, vamos usar a funo de agregao sum:
String jpql ="select sum(m.valor) from Movimentacao m where m.conta=:pConta " + "and m.tipoMovimentacao=:pTipo"; Anteriormente, usamos o mtodo getResultList() do EntityManager para retornar uma lista com os objetos selecionados pela nossa consulta, mas nesse momento ele no nos serve. Queremos retornar apenas um nico valor, no caso o somatrio dos valores. Para isso, vamos usar o mtodo
esquecer de imprimir o valor no console: public class TestaJpqlAvancada { public static void main(String[] args) { EntityManager manager = new JPAUtil().getEntityManager(); Conta conta = new Conta(); conta.setId(3); String jpql = "select sum(m.valor) from Movimentacao m where m.conta=:pConta " + "and m.tipoMovimentacao=:pTipo"; Query query = manager.createQuery(jpql); query.setParameter("pConta", conta); query.setParameter("pTipo", TipoMovimentacao.SAIDA); BigDecimal resultado = (BigDecimal) query.getSingleResult(); System.out.println("Total movimentado ..: R$ " + resultado); } }
Para deixar o nosso cdigo um pouco mais elegante o JPA2 trouxe um novo tipo de objeto para realizarmos queries type safety (que previne erros de tipos de dados), o TypedQuery. Com ele, conseguimos definir o tipo do objeto que vai ser retornado pela nossa query e, com isso, no precisamos ficar fazendo os casts. Para conseguirmos esse objeto, temos que usar a sobrecarga do mtodo createQuery do EntityManager que recebe um segundo parmetro indicando o tipo de retorno: public class TestaJpqlAvancada { public static void main(String[] args) { // trechos omitidos TypedQuery<BigDecimal> query = manager.createQuery(jpql, BigDecimal.class); // trechos omitidos BigDecimal resultado = query.getSingleResult(); System.out.println("Total movimentado ..: R$ " + resultado); } } Repare que agora no precisamos mais fazer o cast, o prprio TypedQuery consegue inferir o tipo de retorno. Ao executar tudo continua funcionando.
Vamos executar uma vez para ver o SQL gerado. Aqui tambm, o Hibernate aplica a funo AVG corretamente.
MovimentacaoDao dao = new MovimentacaoDao(manager); Com essa linha o Eclipse j sabe como criar a classe e o construtor, basta apertar ctrl + 1 para o Eclipse ajudar. A classe fica dentro do pacote
br.com.caelum.financas.dao
public class MovimentacaoDao { private EntityManager manager; public MovimentacaoDao(EntityManager manager) { this.manager = manager; } } Com a classe criada, vamos us-la como se ela j tivesse mtodos. Queremos um mtodo que devolva um Double com a nossa mdia, e que se chame mediaDaContaPeloTipo(...). O mtodo receber a varivel conta e o tipo da movimentao. Novamente o Eclipse gerar o cdigo na classe. Com o mtodo criado falta colar o cdigo da query e devolver o resultado da pesquisa. Repare que o DAO encapsula todos os detalhes da busca com JPA: public class MovimentacaoDao {
private EntityManager manager; public MovimentacaoDao(EntityManager manager) { this.manager = manager; } public Double mediaDaContaPeloTipo(Conta conta, TipoMovimentacao tipo) { TypedQuery<Double> query = manager.createQuery( "select avg(m.valor) from Movimentacao m where m.conta=:pConta " + " and m.tipoMovimentacao = :pTipo", Double.class); query.setParameter("pConta", conta); query.setParameter("pTipo", tipo); return query.getSingleResult(); } } Por fim, vamos executar o mtodo main para ver se tudo continua funcionando. No h supresas, a mdia impressa no console como esperado.
alm do tipo do retorno. Repare que no colocamos mais o JPQL. Costumamos colocar a consulta em cima da entidade. Ento, nesse caso, como nossa consulta relacionada com as movimentaes de uma determinada conta, colocaremos ela na entidade Movimentacao.
Na classe Movimentacao usaremos a anotao @NamedQuery, que recebe dois atributos, o nome da query e o JPQL. esse nome que usamos no mtodo
createNamedQuery(..) do EntityManager. O segundo atributo o JPQL da
query. @NamedQuery(name = "mediaDaContaPeloTipoMovimentacao", query = "select avg(m.valor) from Movimentacao m where m.conta=:pConta and m.tipoMovimentacao = :pTipo") @Entity public class Movimentacao { // trecho omitido }
Agora podemos ver como praticamente no muda nada com o uso das Named Queries. A diferena que em vez de usarmos o mtodo createQuery, usamos o
createNamedQuery
nome. Ao executar o cdigo continua funcionado: public class TestaConsultaFuncoes { public static void main(String[] args) { EntityManager manager = new JPAUtil().getEntityManager(); Conta conta = new Conta(); conta.setId(3); TypedQuery<Double> query = manager. createNamedQuery("mediaDaContaPeloTipoMovimentacao", Double.class); query.setParameter("pConta", conta); query.setParameter("pTipo", TipoMovimentacao.ENTRADA); Double media = query.getSingleResult(); System.out.println(media); } }
Uma vantagem que as Named Queries so verificadas quando o JPA carrega a entidade. Ento se fizermos mudanas no nosso modelo, mas esquecermos de alterar a query recebemos uma exceo antecipadamente.
Uma outra caracterstica imposta pelo uso das Named Queries o uso dos Named Parameter. No tem como concatenar a query na anotao, o que impe logo de incio a boa prtica.
Vimos ento duas formas de organizar as queries, usando o DAO e Named Queries. As duas at podem ser misturadas, usando Named Queries dentro DAO.