EasyCriteira - Facilitando o uso de criteria do JPA

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.

Sérgio, sem querer desviar o assunto principal do tópico, mas fiquei com uma dúvida em relação à sua resposta.

Qual o problema com o padrão DAO, na sua opinião ?

[quote=Rodrigo Sasaki]Sérgio, sem querer desviar o assunto principal do tópico, mas fiquei com uma dúvida em relação à sua resposta.

Qual o problema com o padrão DAO, na sua opinião ?[/quote]

respondi aqui

[quote=Rodrigo Sasaki]Sérgio, sem querer desviar o assunto principal do tópico, mas fiquei com uma dúvida em relação à sua resposta.

Qual o problema com o padrão DAO, na sua opinião ?[/quote]

O problema do DAO é ele mesmo.
Já ouviu falar que o “Hibernate é o seu DAO”?

No princípio o Hibernate não tinha o nome e a confiabilidade que tem hoje, por esta razão inúmeros desenvolvedores costumavam trabalhar de forma a desacoplar o Hibernate.
Com isso, ao invés de facilitar o desenvolvimento, o programador dificultava ainda mais o trabalho em equipe, criando camadas inúteis que só consumiam mais recursos desnecessários.

Entenda que você já tem uma view, um controller e um model, para que criar mais uma camada entre eles? DAO? Injete por dependência uma sessão do Hibernate na camada modelo e utilize-a diretamente, ou, caso não queira tanto, crie um provedor de dados genérico que receba como argumentos criterions e sqlqueries, e retorne esses mesmos objetos de modo que você possa controlar o momento em que os dados serão de fato capturados.

O DAO é um defunto não enterrado, com 300 médicos usando desfibrilador.

Infelizmente trabalho com bancos e aqui não pode sair metendo .jar a torto e a direito, é a realidade da maiorias das empresas com governança corporativa.
Novas iniciativas nesse ambito são sempre bem vindas.

Doravan concordo com voce em genero e numero, pois quando comecei há uns 10 anos já se falava em hibernate e nego tinha medo naquela epoca e por incrivel que pareça, o medo ainda não passou. :lol:
Só acredita nele quem já o utilizou, de fato DAO já devia ter morrido há muito tempo.