EasyCriteira - Facilitando o uso de criteria do JPA

A Criteria Query API é uma das coisas mais pé no saco do JPA2, muito verbosa/trabalhosa/chata/*, acho que só vai chegar perto do que é o LINQ to Entities quando tivermos lambda expressions no Java.

Olhando rápido o projeto, tenho duas sugestões:

  • Pelo que eu vi o projeto vai ser código aberto, porque não colocar no github?
  • A API não suporta Canonical Metamodels? Acho que isso é um “must have” da sua API, criteria perde muito sem isso, na minha opinião.

Parabéns pela iniciativa, nem sei se já existe algo parecido por aí.

Grande Hebert, sempre colaborando com nós mortais programadores JAVA. Valeu cabra!

[quote=jakefrog][quote=DaniloAndrade]Show de bola jakefrog ,

so não gostei muito da assinatura dos metodos

whereEquals
whereIsNull

achei o where nos metodos de restrição repetitivos.

é possivel fazer isso

easyCriteria.whereEquals("houseNumber", 150L).whereIsNull("birthDay")

?

[/quote]É possível fazer link dos comandos sim. [=
Quanto ao where foi a melhor forma que eu encontrei até o momento, uma vez que esse comando identifica alguma condição a ser adicionada. Qualquer idéia é bem vinda! =D[/quote]

Talvez algo do tipo:

easyCriteria.where(equals("houseNumber", 150L), isNull("birthDay"));

Mas aí oq seria o easyCriteria.where(equals(“houseNumber”, 150L), isNull(“birthDay”));? Objetos? Aí eu teria que obrigar o usuário a saber da API interna. Não queria isso. =/

Mas para isso eu já estou tendo mais idéias. obrigado pela força.

[quote=Jairo Junior]A Criteria Query API é uma das coisas mais pé no saco do JPA2, muito verbosa/trabalhosa/chata/*, acho que só vai chegar perto do que é o LINQ to Entities quando tivermos lambda expressions no Java.

Olhando rápido o projeto, tenho duas sugestões:

  • Pelo que eu vi o projeto vai ser código aberto, porque não colocar no github?
  • A API não suporta Canonical Metamodels? Acho que isso é um “must have” da sua API, criteria perde muito sem isso, na minha opinião.

Parabéns pela iniciativa, nem sei se já existe algo parecido por aí.[/quote]E aí Jairo, beleza?
Eu pensei em colocar no github mas eu teria que estudar seu versionamento. =/
Eu sei que é bom e prático mas no momento ñ estou com tempo hábil para entender melhor a ferramenta. =/
Aí eu escolhi o google codes. Pra falar a verdade o código já está lá abertão! =D

Quanto ao Canonical realmente é algo a ser implementado também, só que não por agora. O Canonical é para usuário mais avançados e de primeira instância eu penso em atrair aqueles que tentaram utilizar e não conseguiram, ou até mesmo que estão utilizaram mas ficou verboso. Para o Canonical será necessário uma API mais complexa e por enquanto estou a evitar isso. =D

Como futuras releases eu coloquei na seguinte sequência de prioridade:

  1. Condições where no join. Hoje é possível fazer join, mas sem especificar um where. e: easyCriteria.join(“dogs”).whereEquals(“name”, “floquinho”, dogs);
  2. Paginação
  3. Canonical

É algo que eu estou pensando em fazer. Lógico que pode mudar a ordem. [=

Valeu pela força.

[quote=jakefrog][quote=Jairo Junior]A Criteria Query API é uma das coisas mais pé no saco do JPA2, muito verbosa/trabalhosa/chata/*, acho que só vai chegar perto do que é o LINQ to Entities quando tivermos lambda expressions no Java.

Olhando rápido o projeto, tenho duas sugestões:

  • Pelo que eu vi o projeto vai ser código aberto, porque não colocar no github?
  • A API não suporta Canonical Metamodels? Acho que isso é um “must have” da sua API, criteria perde muito sem isso, na minha opinião.

Parabéns pela iniciativa, nem sei se já existe algo parecido por aí.[/quote]E aí Jairo, beleza?
Eu pensei em colocar no github mas eu teria que estudar seu versionamento. =/
Eu sei que é bom e prático mas no momento ñ estou com tempo hábil para entender melhor a ferramenta. =/
Aí eu escolhi o google codes. Pra falar a verdade o código já está lá abertão! =D

Quanto ao Canonical realmente é algo a ser implementado também, só que não por agora. O Canonical é para usuário mais avançados e de primeira instância eu penso em atrair aqueles que tentaram utilizar e não conseguiram, ou até mesmo que estão utilizaram mas ficou verboso. Para o Canonical será necessário uma API mais complexa e por enquanto estou a evitar isso. =D

Como futuras releases eu coloquei na seguinte sequência de prioridade:

  1. Condições where no join. Hoje é possível fazer join, mas sem especificar um where. e: easyCriteria.join(“dogs”).whereEquals(“name”, “floquinho”, dogs);
  2. Paginação
  3. Canonical

É algo que eu estou pensando em fazer. Lógico que pode mudar a ordem. [=

Valeu pela força.[/quote]

Não tinha achado nenhum link pro google code lá no seu site, pra quem como eu também não achou, segue o link:

http://code.google.com/p/easy-criteria/

Mas aí oq seria o easyCriteria.where(equals(“houseNumber”, 150L), isNull(“birthDay”));? Objetos? Aí eu teria que obrigar o usuário a saber da API interna. Não queria isso. =/

Mas para isso eu já estou tendo mais idéias. obrigado pela força.[/quote]

Isso seria semelhante a Restrictions e Projections do Hibernate. Nâo teria API interna aí no meio. Se você não quiser usar métodos estáticos pode criar um builder pra montar o equals e o isNull do exemplo.

Enfim, é apenas uma forma de facilitar a leitura do código :wink:

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();

Essa API do JPA 2 é das coisas mais porcas que eu já vi na minha vida.

[quote=raf4ever]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();

Essa API do JPA 2 é das coisas mais porcas que eu já vi na minha vida.

[/quote]+1
Realmente eu não gosto dela, mas acho criteria algo muito útil. Por isso criei o EasyCriteria. [=

[quote=Ataxexe]Isso seria semelhante a Restrictions e Projections do Hibernate. Nâo teria API interna aí no meio. Se você não quiser usar métodos estáticos pode criar um builder pra montar o equals e o isNull do exemplo.

Enfim, é apenas uma forma de facilitar a leitura do código :wink: [/quote]Repare que o equals(“houseNumber”, 150L) é um objeto da implementação interna do hibernate. [=
É isso que eu acho de expor api interna. [=

Pessoal, bom dia.

Saiu ontem a nova versão do EasyCriteria! =D

gora é possível adicionar condições a um join:

easyCriteria.innerJoin("dogs", Dog.class); easyCriteria.whereJoinEquals("dogs", "name", "Dark"); easyCriteria.whereJoinStringNotIn("dogs", "name", names); // names is a List<String> easyCriteria.whereJoinStringLike("dogs", "name", "M%"); easyCriteria.whereJoinListIsEmpty("dogs", "cars"); easyCriteria.whereJoinAttributeIsNull("dogs", "nickName"); easyCriteria.whereJoinStringBetween("dogs", "name", "A", "L");É possível também paginar uma consulta:

EasyCriteria<Dog> easyCriteria = EasyCriteriaFactory.createQueryCriteria(getEntityManager(), Dog.class); easyCriteria.setFirstResult(0); easyCriteria.setMaxResults(5);No blog tem um post falando sobre a nova versão: http://uaihebert.com/?p=1567
O site oficial você pode encontrar toda a documentação, road map e dentre outras coisas: http://easycriteria.uaihebert.com/

Muito boa iniciativa! Quando o projeto amadurecer um pouco vamos leva-lo no comitê para ver se ele substitui a porcaria da especificação atual :slight_smile:

Pelo que vi, faltam duas coisas para que se possa realmente fazer qualquer tipo de query:

  • Permitir condições complexas, com combinações de E e OU.
  • Fazer um IN “ao contrário”. O atual permite verificar se o atributo (do registro no banco) está em uma lista de valores; o contrário seria ver se o valor fornecido é igual a um dos valores em um atributo de lista. Por exemplo, cliente tem associação com uma lista de cachorros, pesquisar todos os clientes que tem um cachorro de nome Rex.

Mas aí oq seria o easyCriteria.where(equals(“houseNumber”, 150L), isNull(“birthDay”));? Objetos?[/quote]
Dessa maneira traria mais flexibilidade, fica mais fácil de atender ao primeiro item que coloquei lá em cima.

// Cria restrições
EasyRestriction restrictionHouseNumber = EasyRestriction.isEqual("houseNumber", 150L); // Acabei de inventar a EasyRestriction para exemplificar
EasyRestriction restrictionNullBirthday = EasyRestriction.isNull("birthDay");
// Passa os objetos Restriction para a query
easyCriteria.where(restrictionHouseNumber, restrictionNullBirthday);

// Ou simplificando em uma linha, chegamos proximo do que o Ataxexe colocou:
easyCriteria.where(EasyRestriction.isEqual("houseNumber", 150L), EasyRestriction.isNull("birthDay"));

// Se usarmos static import aí fica igualzinho
// Na verdade só troquei o nome do equals para diferenciar do Object.equals(o)
easyCriteria.where(isEqual("houseNumber", 150L), isNull("birthDay"));

Aí dá para aproveitar a estrutura para criar restrições compostas:

EasyRestriction restriction1 = EasyRestriction.or(EasyRestriction.isEqual("houseNumber", 150L), EasyRestriction.isNull("birthDay"));
EasyRestriction complicated = EasyRestriction.and(restriction1, EasyRestriction.greaterThan("age", 18));
easyCriteria.where(complicated);

// Ou colocando tudo em uma linha e usando static import:
easyCriteria.where(and(or(isEqual("houseNumber", 150L), isNull("birthDay")), greaterThan("age", 18)));

Mas nada impediria de ter os métodos where… (como está hoje) como um shortcut para as querys mais simples, também seria bem útil.

Olá gomesrod,

Já adicionei o or para entrar na próxima versão. [=

Quanto ao In invertido, você poderia fazer:EasyCriteria<Person> easyCriteria = EasyCriteriaFactory.createQuery(em, Person.class); easyCriteria.whereJoinEquals("dogs", "name", "Rex"); Desse modo você iria trazer todas as pessoas que tem um cachorro chamado Rex! =D

Quanto criar os objetos do tipo: isEqual, or, and e demais ainda não sei.

Eu fiz uma pesquisa e uns 85% das pessoas disseram que do modo como está fica mais fácil de iniciar o uso. (na boa, consultei muita gente q eu conheço que saca de desenvolvimento).
Tendo objetos como listado acima, seria mais classes que o usuário desenvolvedor teria que conhecer.
Mas não desconsiderei sua opinião não, tenho pensado sobre isso. =D

[quote=jakefrog]EasyCriteria<Person> easyCriteria = EasyCriteriaFactory.createQuery(em, Person.class); easyCriteria.whereJoinEquals("dogs", "name", "Rex");
Desse modo você iria trazer todas as pessoas que tem um cachorro chamado Rex! =D
[/quote]
Não tinha pensado que funcionava também com relacionamentos ToMany. Se é assim sim!

[quote=jakefrog]
Quanto criar os objetos do tipo: isEqual, or, and e demais ainda não sei.

Eu fiz uma pesquisa e uns 85% das pessoas disseram que do modo como está fica mais fácil de iniciar o uso. (na boa, consultei muita gente q eu conheço que saca de desenvolvimento).
Tendo objetos como listado acima, seria mais classes que o usuário desenvolvedor teria que conhecer.
Mas não desconsiderei sua opinião não, tenho pensado sobre isso. =D[/quote]
O ideal para mim é ter as duas opções, simplicidade para quem quer algo simples e flexibilidade para quem quer algo complicado.
Com sua resposta percebi que a proposta do projeto é realmente se focar no simples, quem quiser ir além utiliza a api do JPA direto.

Muito boa a iniciativa. A suposta praticidade do critéria sempre foi discutível para mim. Agora parece que o negócio realmente ficou simples, rs.

[quote=luzales]Muito boa a iniciativa. A suposta praticidade do critéria sempre foi discutível para mim. Agora parece que o negócio realmente ficou simples, rs.[/quote]Opa! Valeu! =D
Estou refatorando muita coisa nele agora para lançar a condição OR dele. =D

A vantagem do TDD com JUnit é que dá para ver se deu erro na hora! =D

[quote=jakefrog]
A vantagem do TDD com JUnit é que dá para ver se deu erro na hora! =D[/quote]

É verdade. Embora o tempo de desenvolvimento possa aumentar um pouco, o esforço compensa.

[quote=Hebert Coelho][quote=luzales]Muito boa a iniciativa. A suposta praticidade do critéria sempre foi discutível para mim. Agora parece que o negócio realmente ficou simples, rs.[/quote]Opa! Valeu! =D
Estou refatorando muita coisa nele agora para lançar a condição OR dele. =D

A vantagem do TDD com JUnit é que dá para ver se deu erro na hora! =D[/quote]

Então Hebert, já lançou a versão com a condição OR? Isso pra mim é fundamental.

[quote=Ataxexe][quote=jakefrog][quote=DaniloAndrade]Show de bola jakefrog ,

so não gostei muito da assinatura dos metodos

whereEquals
whereIsNull

achei o where nos metodos de restrição repetitivos.

é possivel fazer isso

easyCriteria.whereEquals("houseNumber", 150L).whereIsNull("birthDay")

?

[/quote]É possível fazer link dos comandos sim. [=
Quanto ao where foi a melhor forma que eu encontrei até o momento, uma vez que esse comando identifica alguma condição a ser adicionada. Qualquer idéia é bem vinda! =D[/quote]

Talvez algo do tipo:

easyCriteria.where(equals("houseNumber", 150L), isNull("birthDay"));

Not bad. E não necessariamente o usuário precisaria conhecer a API interna, se tivesse algo tipo:

easyCriteria.where(Conditions.equals("houseNumber", 150L), Conditions.isNull("birthDay"));

Tu poderia, inclusive, considerar operadores lógicos como conditions “or” e “and”. Tipo ..where(Conditions.or(Conditions.isNull("birthDay"), Conditions.equals("birthDay", "13;05;1987"))

E um import static resolveria o problema da verbosidade.

Gostei muito da sua ideia. Parabéns. Eu mesmo já tinha pensando em pegar a API de criteria do middlheaven e separá-la para poder usada “a vulso” como essa.
O que vc chama de “link de métodos” é "“encadeamento de métodos” (method channing). Link de métodos é outra coisa, é vc criar atalhos para métodos que são muito usados.
Fez muito bem usar a ideia dos metodos encadeados em vez dos métodos estáticos que o hhibernate usa. Mas tenha em mente que isso pode limitar a api.
Pelo que vi vc encadeia os métodos suponto “And” entre eles. Mas para uma API robusta vc precisa de OR também e poder mixar AND e OR. O Hibernate faz isso obrigado a criar objetos diferentes e realmente para uma api de métodos encadeados não é nada fácil (eu sei porque tenho esse problema na minha api que é mais generica que orm (pode ser usada para procurar texto com lucene) e a extenção de orm fica aqui)

Um detalhe é que a sua API apenas suporta jpa - pelo que entendi - isso é uma desvantagem. Se ela suportar hibernate normal (sem ser jpa) seria mais vantajoso.
PAra fazer isso separe a API de criteria do executor da criteria. Isso lhe vantagem para executar a mesma query contra várias fontes ( e mais tarde pode até fazer contra nosql). Idealmente teria uma classe/interface que o usuaário poderia implementar para suportar outras fontes de dados.

Em vez disto

EasyCriteria criteria  = EasyCriteriaFactory.createQueryCriteria(getEntityManager(), Dog.class);  

use isto

EasyCriteria criteria  = EasyCriteriaBuilder.createQueryCriteria(Dog.class);  // builder, não factory. O factory cria sozinho, o builder ajuda o programador a criar


EntityManagerExecutor executor = new EntityManagerExecutor (entitymanager);
// ou  HibernateExecutor executor = new HibernateExecutor (session);

QueryResult result = executor .query(criteria);

Não é legal que o criteria tenha o getResultList() isto é um acoplamento desnecessário.
O EntityManagerExecutor vc pode usar injeção para colocar nas suas classes em vez do entitymanager direto e o efeito é o mesmo.

Para as restrições use as abreviações comuns como eq, lt, isNull, isEmpty, contains, starsWith, between, etc… não use equals para eq que dá problema com a nomenclatura padrão do java. Não use “with”, é um prefixo artificial que só alonga a escrita ( programadores de verdade não usam complete do IDE :twisted: :slight_smile: )
Uma técnica que é util é ao encadear os métodos retornar um objeto diferente que tem só os métodos que podem ser usados naquele momento. Com isso vc consegue o agrupamento que vc falou. Ai poderia fazer algo como :


criteria.restrict("name").eq("Sergio").and("age").eq(18).or("age").eq(12).or('age").between(20, 30)

Repare que o restricte o and/or servem para dizer o nome do campo e o valor do operador vai junto dele.
quando vc usa restrict, and ou or, o retorno é um objeto que só tem os operadores. Desa forma o cara não pode fazer and(‘a’).and(‘b’) porque a api não deixa fazer isso por design.
quando o cara usa o operador, ai vc pode voltar ao objeto inicial antes de dar o restrict/and/or. Este mecanismo de method chaning do builder permite que a sua interface seja tão fluente quanto a sua imaginação deixar ( e a sintaxe do java deixar. tem coisas que dá um pouco de raiva não serem possíveis no java).

Não amarre a sua api à api do jpa e vc terá uma ferramente muitas vezes mais poderosa que pode ajudar as pessoas em operações de migração, na implementação correta do padrão Repositorio, e se Deus quiser, na extinção dos DAOs :lol: :lol: :lol:

Parabéns, continue que vai bem. Se precisa de ajuda , é só dizer.
A ideia é esta, na prática tem alguns truques necessários e uso pesado de generics. Dê uma olhada na minha api.