Hospedagem Profissional

Hospedagem Profissional
Clique aqui e ganhe US$ 10,00 para testar durante 1 mês a melhor hospedagem: Digital Ocean!

sexta-feira, 21 de novembro de 2008

Hibernate Criteria com subquery

É realmente impressionante como o Hibernate pode fazer consultas sql usando Criteria. Ontem precisei fazer uma consulta e cheguei à conclusão que seria necessário o uso de subquery.

Primeiro, fiz a consulta por um query console do meu banco para ter certeza. E um pouco descrente de que Criteria iria resolver o meu problema 100%, procurei por subquery na documetação do Hibernate.

Encontrei a solução e, para a minha surpresa, a consulta sql gerada foi exatamente a que eu havia feito no query console do meu banco de dados.

Então, vamos ao exemplo!

Suponhamos que temos registros de frutos e que, cada fruto contém uma lista de vitaminas:


Fruit: Pineapple
--Vitamins: [Vitamin C, Vitamin B6]
Fruit: Orange
--Vitamins: [Vitamin C, Vitamin B6]
Fruit: Banana
--Vitamins: [Vitamin C, Vitamin A]

Nossas classes, já mapeadas com annotations, ficariam assim:

Fruit.java:


JAVA:
  1. @SequenceGenerator(name = "sq_fruit", sequenceName = "sq_fruit")
  2. public class Fruit {

  3. @Id
  4. @GeneratedValue(strategy = GenerationType.AUTO, generator = "sq_fruit")
  5. private Integer id;
  6. private String name;
  7. @ManyToMany(cascade = CascadeType.ALL)
  8. @ForeignKey(name = "fk_Fuit", inverseName = "fk_Vitamin")
  9. @JoinTable( name = "Fuits_Vitamins",
  10. joinColumns = @JoinColumn(name = "Fruit_id"),
  11. inverseJoinColumns = @JoinColumn(name = "Vitamin_id"))
  12. private List<Vitamin> vitamins;

  13. // getters, setters...

  14. }

Vitamin.java:


JAVA:
  1. @SequenceGenerator(name = "sq_vitamin", sequenceName = "sq_vitamin")
  2. public class Vitamin {

  3. @Id
  4. @GeneratedValue(strategy = GenerationType.AUTO, generator = "sq_vitamin")
  5. private Integer id;
  6. private String name;

  7. // getters, setters...

  8. }

Em uma busca simples, poderíamos recuperar uma lista de todas os frutos que contém a vitamina C:


JAVA:
  1. Criteria criteria = session.createCriteria(Fruit.class, "fruit");
  2. criteria.createAlias("fruit.vitamins", "vitamin");
  3. criteria.add(Restrictions.eq("vitamin.name", "Vitamin C"), Criteria.LEFT_JOIN);

  4. List fruits = criteria.list();

  5. for (Fruit f: fruits) {
  6. System.out.println("Fruit: " + f.getName());
  7. System.out.println("--Vitamin: " + f.getName());
  8. }

Como pedimos, esta consulta retorna uma lista de frutos. Porém, cada fruto retornado conterá apenas uma vitamina: a vitamina C!


Fruit: Pinnapple
--Vitamin: Vitamin C
Fruit: Orange
--Vitamin: Vitamin C
Fruit: Banana
--Vitamin: Vitamin C

Foi exatamente o que pedimos quando adicionamos Restrictions.eq("vitamin.name", "Vitamin C") para a criteria.

Até aqui tudo bem, se apenas fossem necessárias os frutos. E se precisássemos agora fazer a mesma consulta (por "vitamica C"), mas gostariámos de ver todas as vitaminas que cada fruto contém? Usamos subquery!


JAVA:
  1. // todos frutos que contém a vitamina C
  2. DetachedCriteria dc = DetachedCriteria.forClass(Fruit.class, "fruit");
  3. dc.createAlias("fruit.vitamins", "vitamin", Criteria.INNER_JOIN);
  4. dc.add(Restrictions.eq("vitamin.name", "Vitamin C"));
  5. dc.setProjection(Property.forName("fruit.id"));

  6. // mas quero ver as outras vitaminas que o fruto tem
  7. Criteria criteria = session.createCriteria(Fruit.class, "fruit");
  8. criteria.createAlias("fruit.vitamins", "vitamin", Criteria.LEFT_JOIN);
  9. criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY);
  10. criteria.add(Property.forName("fruit.id").in(dc));

  11. List list = criteria.list();

  12. for (Fruit fruit : list) {
  13. System.out.println("Fruit: " + fruit.getName());
  14. System.out.println("--Vitamins: " + fruit.getVitamins());
  15. }

O método in() da classe Property recebe uma DetachedCriteria. Uma DetachedCriteria nos permite criar uma consulta fora de uma sessão, para ser executada posteriormente em uma sessão arbitrária.

A saída no console, com o logger da query:


JAVA:
  1. Hibernate:
  2. select
  3. this_.id as id1_1_,
  4. this_.name as name1_1_,
  5. vitamins3_.Fruit_id as Fruit1_3_,
  6. vitamin1_.id as Vitamin2_3_,
  7. vitamin1_.id as id0_0_,
  8. vitamin1_.name as name0_0_
  9. from
  10. Fruit this_
  11. left outer join
  12. Fuits_Vitamins vitamins3_
  13. on this_.id=vitamins3_.Fruit_id
  14. left outer join
  15. Vitamin vitamin1_
  16. on vitamins3_.Vitamin_id=vitamin1_.id
  17. where
  18. this_.id in (
  19. select
  20. fruit_.id as y0_
  21. from
  22. Fruit fruit_
  23. inner join
  24. Fuits_Vitamins vitamins3_
  25. on fruit_.id=vitamins3_.Fruit_id
  26. inner join
  27. Vitamin vitamin1_
  28. on vitamins3_.Vitamin_id=vitamin1_.id
  29. where
  30. vitamin1_.name=?
  31. )

Fruit: Pineapple
--Vitamins: [Vitamin C, Vitamin B6]
Fruit: Orange
--Vitamins: [Vitamin C, Vitamin B6]
Fruit: Banana
--Vitamins: [Vitamin C, Vitamin A]

Tem outro exemplo aqui, usando Detached queries and subqueries.

Por Rodrigo Facholi em http://blog.dclick.com.br/2008/10/09/hibernate-criteria-com-subquery/pt/

segunda-feira, 3 de novembro de 2008

Mentawai 1.14.1 Lançada,babem !!!!


Galera, foi lançada a versão 1.14.1 do Mentawai, confesso que algumas das novidades realmente me deixaram muito feliz.

Velhas solicitaçãos dos adeptos deste framework foram atendidas, como o MentaBlank, a modelo do StrutsBlank, DateFilter para uma converção correta de dados do tipo data informados na jsp, e uma forma de mudar o usuário logado sem ter de fazer logoff antes, entre outras.

Mas algumas novidades que me surpreenderam foram :
- IPFilter
- ExecUtil
- ImageMinSizeRule
- ImageUtils
- SendLater
- DateUtils

Veja a lista completa de mudanças abaixo e suas respectivas explicações:

- Projeto MentaBlank.zip: ponto de partida facilitado para qualquer aplicação web com o Mentawai

- getStringValue, getBooleanValue, getIntValue, etc. são agora getString, getBoolean, getInt, etc.
Os métodos antigos foram depreciados.

- getStringValues e getIntValues são agora getStrings e getInts. Os métodos antigos foram depreciados.

- IpFilter para permitir o acesso a uma action de apenas requisições vindas de certos IPs.

- ExecUtil para permitir facilmente a execução de processos externos
(Java é muito pentelho em relação a isso...)

- ImageMinSizeRule para validar o tamanho (dimensão) mínimo de uma imagem recebida num request.

- ImageUtils para fazer crop, resize, conversão e outras operações com imagens que chegaram via upload.

- Possibilidade de configurar filtros específicos para uma ou mais classes de Action.
(Antes só podia especificar isso numa ActionConfig)

- sendLater para enviar email de forma assíncrona sem bloquear a requisição web.

- melhorias no tag de paginação (paginatorTag)

- loadListMinus e buildSelectMinus para permitir carregar uma lista de beans excluindo certos campos

- DateUtils para facilitar o trabalho com dates.

- FileUploadFilter atualizado para trabalhar com o último commons FileUpload (1.2.1)

- DateFilter para criar um java.util.Date a partir de um dia, mês e ano no input
(usando o locale correto)

- Listas padrão para dias do mês e anos (apenas números)

- DIFilter agora é AutoWiringFilter (antigo foi depreciado)

- método replaceUserSession para trocar o usuario da sessao sem reiniciar/invalidar a sessao

- não precisa mais especificar a classe do ApplicationManager no web.xml. O framework faz
um scan e descobre sozinho agora.

- setReloadable para recarregar o application manager quando este for modificado.
Precisa do excelente produto ZeroTurnaround

- correções de bugs e muitas outras melhorias

Para que não sabe oquê é o framework Mentawai, confira o seguinte post do nosso blog :
- http://i9webjava.blogspot.com/2008/10/voc-j-ouviu-falar-do-framework-mentawai.html

Mais informações :
- Site Oficial : http://www.mentaframework.org
- Forum Oficial : http://forum.mentaframework.org/forums/list.page