EasyCriteria 2.0 – JPA Criteria tem que ser simples

Olá, tudo bem?

Muito tempo se passou desde meu último post, mas não estava parado durante esse tempo.

O post de hoje vem falar sobre a nova versão do Framework chamado EasyCriteria. Ao final deste pequeno post eu conto mais o que estar por vir. [=

Infelizmente um grande problema da Criteria do JPA é sua verbosidade. Por que não facilitar? Foi pensando desse modo que nasceu o framework EasyCriteria e agora a recente versão 2.0.

Para fazer um simples select que busque todas as linhas do banco de dados, o seguinte código seria necessário:

CriteriaQuery<Person> criteriaQuery = criteriaBuilder.createQuery(Person.class);
Root<Person> root = criteriaQuery.from(Person.class);
criteriaQuery.select(root);
TypedQuery<Person> query = entityManager.createQuery(criteriaQuery);
query.getResultList();

Note quanto trabalho para apenas reproduzir a JPQL : select p from Person p.

Agora, veja como o EasyCriteria facilita a construção da mesma Criteria acima:

EasyCriteria<Person> easyCriteria = EasyCriteriaFactory.createQuery(entityManager, Person.class);
easyCriteria.getResultList();

A diferença da versão 1.0 e 2.0 está na redução de métodos e na criação de métodos genéricos que facilitem a utilização do projeto. Para comparar valores com os símbolos =, >, >=, <=, < e outro mais, basta fazer como abaixo:

easyCriteria.andGreaterThan("hairSize", 10.4f); // >

easyCriteria.andGreaterOrEqualTo("height", 11.00d); // >=

easyCriteria.andLessThan("totalBooksOwned", 30L); // <

easyCriteria.andLessOrEqualTo("firstJobDate", firstJobDate); // <=

easyCriteria.andJoinEquals("dogs", "age", 15); // =

easyCriteria.andJoinStringIn("dogs", "name", names); // value in (x, i, z, ...)

easyCriteria.andJoinStringLike("dogs", "name", "%y");

Uma ideia fixa do EasyCriteria é expor o menor número de API possível ao usuário. Visando essa ideia, a API incorporou o “OR” de uma query sem a necessidade expor outras classes.

Veja como fazer um “OR” simples:

select s from Song s where s.id = 1 or s.length = 40 or s.artist = 'Group 1 Crew'
easyCriteria.orEquals("id", 1).orEquals("length", 40).orEquals("artist", "Group 1 Crew");

E também poderia ser feito o seguinte tipo de query:

select s from Song s where (s.id = 1) or (s.id = 2) or (s.length = 40) or (s.artist = 'Group 1 Crew')
easyCriteria.orEquals("id", 1, 2).orEquals("length", 40).orEquals("artist", "Group 1 Crew");

E para casos mais complexos como a query abaixo, também é possível reproduzir com o EasyCriteria:

select s from Song s where (s.totalDownloads = 20 or s.weight = 10.00) and (s.price = 20.00 or s.type = :type)
easyCriteria.orEquals(1, "totalDownloads", 20L).orEquals(1, "weight", 10.00f).orEquals(2, "price", 20.00d).orEquals(2, "type", SongType.PRAISE);

Foi criada a ideia de índice para cada OR, ou seja, o primeiro grupo de OR é composto por totalDownloads e weight, já o seguinte grupo é price e type.

E como valor padrão o índice 1 é sempre utilizado. A criteria acima poderia ser traduzida por:

easyCriteria.orEquals("totalDownloads", 20L).orEquals("weight", 10.00f).orEquals(2, "price", 20.00d).orEquals(2, "type", SongType.PRAISE);

Para uma query que inverta esse quadro, onde AND é separado por OR basta fazer como abaixo:

select s from Song s where (s.id = 1 and s.name = 'Sing Out') or (s.id = 2 and s.name = 'Alive')
easyCriteria.addAndSeparatedByOr(1, "id", 1).addAndSeparatedByOr(1, "name", "Sing Out").addAndSeparatedByOr(2, "id", 2).addAndSeparatedByOr(2, "name", "Alive");

É isso pessoal, espero que vocês gostem da novidade. O framework está longe de se considerar pronto. E para bolar um modo de criar o OR foram queimados muitos neurônios com ajuda do João Neves (http://about.me/joaonevesfilho) e também o Sasaki (http://curriculum.rodrigosasaki.com/).

Aqui é possível ver a página oficial do framework: http://easycriteria.uaihebert.com. E o melhor, é free e open source (http://code.google.com/p/easy-criteria/).

Outra coisa legal é o fato de o projeto ter 100% de cobertura com plugin Cobertura e foi testado com OpenJPA, EclipseLink e Hibernate. É aí que eu peço a sua ajuda, pois foram encontrados bugs em todas implementações citadas. Seria possível você votar para que o bug seja resolvido?

EclipseLink: https://bugs.eclipse.org/bugs/show_bug.cgi?id=386354
OpenJPA: https://issues.apache.org/jira/browse/OPENJPA-2333
Hibernate: https://hibernate.onjira.com/browse/HHH-7985

E o que vem por aí? Em primeiro lugar eu demorei escrever um novo post, pois estou finalizando meu primeiro livro. Se Deus quiser até março ele será lançado.

E em segundo lugar estudei bastante Maven nesse tempo e pretendo lançar um próximo post de um mini livro só sobre ele contendo um básico e aplicações completas. Sim “aplicações” no plural mesmo.

Até a próxima pessoal! o_

10 thoughts on “EasyCriteria 2.0 – JPA Criteria tem que ser simples

    • Opa, tudo bem?

      Que nada, concordo com você.

      Esse vai ser o próximo passo. =D

      Estou tentando descobrir como. [=

      Obrigado pelo apoio.

    • Raphael, bom dia.

      Estamos em um processo de aprovação por parte do repositório do Maven.

      Já estamos na etapa final e embreve estaremos no repositório oficial deles! o/

      Obrigado pelo apoio.

  1. Olá Hebert, postei no guj o problema que estou tendo. Estou tentando utilizar o EasyCriteria mas estou obtendo um erro, você até comentou alguma coisa.
    java.lang.NoClassDefFoundError: com/uaihebert/factory/EasyCriteriaFactory
    Adicionei no projeto que fiz pelo seu exemplo: http://uaihebert.com/?p=836
    Não sei se vc teria alguma sugestão do que fazer..

    • Leandro, boa tarde.

      Fico feliz por ver no post que seu problema foi resolvido empacotando a dependência no EAR.

      Obrigado pela visita e por utilizar o EasyCriteira.

  2. Olá Hebert,

    Excelente API,está de parabéns!
    Estou com uma dúvida em relação ao “case” do valor que é retornado. Por exemplo:

    easyQuery.andStringLike(“titulo”, “%” + filtro.getTitulo().toUpperCase() + “%”);

    Gostaria de saber se tem um modo de que o campo título fique maíusculo para que possa ser comparado com o valor do parâmentro passado. No Criteria padrão seria o CriteriaBuilder.upper();

    Obigado.

    • Pedro, boa tarde.

      Agradeço o feedback sobre o framework.

      Essa semana vai sair uma nova versão contendo a função lowerCase.

      Creio que ajudará e muito. [=

      Obrigado pelo apoio e desculpe a demora.

  3. Olá hebert bom dia!

    Parabéns por esta “mão na roda”!

    Minha dúvida é a seguinte:

    Estou utilizando Spring com Hibernate 4 e meus metodos CRUD utilizam Session em vez de EntityManager.

    Como eu posso utilizar a Session em vez da EntityManager?

    Desculpe se falei bobagem! :D

    • Tiago, bom dia.

      Infelizmente não tenho nenhum exemplo aqui de como fazer isso.

      Uma solução simples seria postar sua dúvida no stack overflow, o pessoal lá é fera.

      Depois me fala a solução por favor? [=

      Obrigado

Leave a Comment