Skip to content

Criteria Toolbox

Será raro o software de negócio que não trabalhe com algum tipo de dado. Uma das operações mais comuns neste tipo de sistema é com certeza a de procurar dados conforme alguma critério. A Criteria Tooblox é a resposta do MiddleHeaven a como definir, de forma independente, um critério de busca de dados.

A Criteria Tooblox especializa-se em construir objetos Criteria. “Criteria” é o plural de “Criterion” (critério), portanto, um objeto de criteria é um conjunto de objetos criterion. O objeto Criteria segue o padrão QueryObject em que um objeto único contém toda a informação necessária para definir uma pesquisa contra um repositório de dados.

A construção de um objeto Criteria é mediada por um CriteriaBuilder que segue o padrão Builder Isso torna a construção simples, fluente e fortemente tipada.

A Criteria Tooblox constrói critérios de pesquisa baseados em objetos mas não os executa. Esse papel é deixado a outras toolboxes que implementam a real pesquisa contra um repositório.

Pesquisas

Todos

A primeira pesquisa que queremos conseguir é obter todas as instancias de uma certa classe que possam existir no repositório. Para uma classe Subject teriamos:

1
2 Criteria<Subject> all = CriteriaBuilder.search ( Subject. class ) .all () ;
3

Código 1: Exemplo de pesquisa por todos

Que se pode ler como “Pesquisa (search) por objetos da classe Subject e obtém todos (all)”.

O método search é estático, portanto, se desejar pode usar o recurso de importe estático (import static) e simplificar o codigo :

1
2 Criteria<Subject> all = search ( Subject. class ) .all () ;
3

Código 2: Usando Static Import

Contudo, esta opção não é recomendada já que as Boas Práticas indicam que métodos estáticos devem ser chamados explicitamente na interface que os define. Você decide.

Esta pesquisa é simples, mas normalmente gostaríamos de mais algum refinamento.

Por atributos

Como o critério apenas será aplicado a objetos a forma de refinar a pesquisa é estabelecendo restrições para os seus atributos. Imaginemos que Subject tem um atributo “name”. A pesquisa seguinte encontrará “Todos os Subject cujo name não é exatamente Brian

1
2 Criteria<Subject> brians = search ( Subject. class )
3 .and ( “name” ) .not () .eq ( “Brian” )
4 .all () ;
5

Código 3:

O operador and adiciona a restrição pelo nome à pesquisa original que sempre encontra todos. O operador not nega o operador seguinte, no caso o operado de igualdade, gerando o operador “diferente de”.

Podemos restringir a pesquisa o quanto quisermos:

1
2 Criteria<Subject> danielAtivos = CriteriaBuilder.search ( Subject. class )
3 .and ( “name” ) .not () .startsWith ( “Daniel” )
4 .and ( “active” ) .not () .eq ( false )
5 .all ()
6

Código 4: Pesquisa com mais restrições

O operador “and” pode ser utilizado repetidamente. Note-se que escrevemos uma dupla negação procurando pelos Subject cujo atributo “active” não é falso. Isto pode parecer que é o mesmo que procurar aqueles cujo atributo “active” é verdadeiro. Isso só é verdade se o atributo “active” só tiver dois estados. Se ele puder conter o valor null,por exemplo, as duas pesquisas não são mais equivalente.

Uma outra diferença é o uso de “startsWith” que procura por objetos cujo valor do atributo começa com um certo texto. Este operador só funciona para atributos textuais.

Uma visita à interface Constraint irá mostrar todos os operadores que podem ser utilizados:

  • eq -igual a
  • lt – menor que
  • gt – maior que
  • le – menor ou igual a
  • ge – maior ou igual a
  • startsWith – começa com
  • endsWith – acaba com
  • contains – contém
  • in – está contido em um intervalo ou conjunto de valores
  • bewteen – está contido entre dois valores
  • not – nega a condição de restrição seguinte. Usado para negar todos os outros operadores

Ordenação

Restringir a pesquisa é uma capacidade importante, mas também o é, ser capaz de ordenar o resultado da pesquisa. A Criteria Tooblox permite isso de uma forma muito simples:

1
2 Criteria<Subject> bornInXXcentury = CriteriaBuilder.search ( Subject. class )
3 .and ( “birthday” ) .bewteen (
4 CalendarDate.date ( 1900 , 1 , 1 ) ,
5 CalendarDate.date ( 2000 , 12 , 31 )
6 )
7 .orderBy ( “birthday” ) .asc ()
8 .all ()
9

Código 5: Pesquisa com ordenação

O operador orderBy permite escolher por qual atributo queremos ordenar e em qual direção queremos que a ordenação seja feita (asc – ascendente ou desc – descendente). Não pode ser mais simples que isto. O operador orderBy pode ser utilizado repetidamente para criar ordenação por múltiplos atributos. Contudo é preciso notar que a sequencia em que os critérios de ordenação são adicionados é relevante para o resultado já que o MiddleHeaven irá ordenar os dados primeiro pelo primeiro critério adicionado, depois pelo segundo, etc…

Fluência

Escrever um critério de pesquisa pode ser extenso. A fluência do CriteriaBuilder permite que se escreva o critério como se em língua natural o que facilita tanto a escrita como a posterior leitura.  Obter fluência na escrita do critério é um dos objetivos principais da Criteria Tooblox e conseguido através de diferentes técnicas de encadeamento de métodos e encadeamento de construtores. Experimente no seu editor preferido com suporte a auto-complete. Verá que, por exemplo, após escrever “orderBy” as únicas opções possíveis a seguir são escrever “asc” ou “desc” o builder controla as suas opções à medida que escreve evitando erros.

Comparemos um critério criado como a Criteria Tooblox com um criado como o Hibernate ( que também suporta o padrão QueryObject) e o tradicional SQL

1
2 SELECT *
3 FROM Subject
4 WHERE name LIKE ‘%d e% ‘
5 ORDER BY birthday ASC
6 SQL equivalente
7

Código 6: SQL equivalente

1
2 Criteria criteria = hibernateSession.createCriteria ( Subject. class ) ;
3 .add ( Restrictions.like ( “name” , “%de%” ) )
4 .addOrder ( Order.asc ( “birthday” )) ;
5

Código 7: Código com Hibernate

1
2 Criteria<Subject> criteria = CriteriaBuilder.search ( Subject. class ) ;
3 .and ( “name” ) .contains ( “de” )
4 .orderBy ( “birthday” ) .asc ()
5 .all () ;
6

Código 8: Código com MiddleHeaven Criteria Toolbox

Semelhante, mas as diferenças são importantes. O principal problema com outras API de critérios é que para criar o critério é preciso já ter acesso a algum objecto especial da API que não diz respeito a critérios e sim ao repositório. No caso do Hibernate é necessário ter acesso ao objeto Session. A Criteria Tooblox é totalmente independente. Desta forma, o critério pode ser criado em qualquer ponto do sistema e até serializado se necessário.

Embora pareça que a API do Hibernate é fluente, ela não o é realmente porque necessita de vários métodos estáticos – especialmente os existentes nas classes Restrictions e Order – para construir o critério. Além disso a sintaxe é amarrada a banco de dados já que “like” é um operador de banco de dados e o uso do sinal de porcentagem (%) é necessário para a API JDBC. A Criteria Tooblox não contém nenhuma dependência com bancos de dados ou a API JDBC. Isto permite que o critério seja aplicado a qualquer tipo de repositório de dados ( inclusive os que usam JDBC) e permite trocar o repositório sem mudar o critério. Sendo que o critério de pesquisa é onde está a logica do negocio/domínio a preservação do critério é muito importante para não introduzir erros no sistema.

A Criteria Tooblox permite escrever critérios de uma forma muito próxima da tradicional SQL que a maioria dos desenvolvedores domina, facilitando a transição. Para os novatos, o controle que a Criteria Toolbox impõe na sintaxe elimina erros de quem está aprendendo, além do que os permite escrever critérios que podem ser executados não apenas sobre bancos de dados, mas sobre muitos outros suportes de dados, como colecções, por exemplo.

Por detrás dos panos

O poder da Criteria Tooblox advém completamente da capacidade de orientação a objetos e tipos genéricos da linguagem Java, do padrão Builder , da técnica de encadeamento de métodos (method channing) e da técnica de encadeamento de builders (não ha um nome para isso ainda no mainstream, mas o Martin Fowler batizou uma ideia semelhante com o nome “Progressive Interface”).

Ou seja, o poder da MiddleHeaven Criteria Tooblox além de orientação a objetos pura. Em um tempo em que ferramentas e API de manipulação de código são comuns é bom saber que ainda podemos ir longe com o uso dessas técnicas de tunning envenenadas.

A completa independência da Criteria Tooblox do repositório em que o critério seja executado permite que o mesmo critério possa ser usado para diferentes repositórios. Contudo isso também significa que a Criteria Toolbox não pode utilizar informação do modelo para ajudar a criar os critérios e validar as restrições. Isso é feito apenas no momento em que o critério é submetido ao repositório de dados.

Execução

Neste momento deve se estar perguntando como executar a pesquisa. Isso é feito por outra toolbox, mas aqui fica uma ideia de como funciona

No MiddleHeaven os principais repositórios de dados são objetos DataStorage que pertencem à Storage Toolbox. A execução é feita através de objectos Query que são criados pelo próprio DataStorage:

01
02 // define a pesquisa
03 Criteria<Subject> criteria = CriteriaBuilder.search ( Subject. class ) ;
04 .and ( “name” ) .contains ( “de” )
05 .orderBy ( “birthday” ) .asc ()
06 .all () ;
07
08 // define a forma de execução
09 Query<Subject> query = dataStorage.createQuery ( criteria ) ;
10
11 // executa realmente
12 List<Subject> subjects = query.findAll () ;
13

Código 9:

ou, simplesmente :

01
02
03 List<Subject> subjects = dataStorage.createQuery (
04 CriteriaBuilder.search ( Subject. class ) ;
05 .and ( “name” ) .contains ( “de” )
06 .orderBy ( “birthday” ) .asc ()
07 .all ()
08 ) .findAll () ;
09
10

Código 10:

O objeto intermediário Query permite executar o mesmo critério contra o mesmo repositório de dados repetidas vezes sem passar pelo objecto de dataStorage todas as vezes. Desta forma o objeto Query pode ser criado apenas uma única vez, guardado, e depois executado quando necessário. Por outro lado, a execução só acontece quando os métodos de Query são chamados. Diferentes métodos resultam em diferentes estratégias e é isso que dá flexibilidade e performance ao mecanismo. Mais detalhes dessas técnicas na descrição da Storage Toolbox.

Deixe um Comentário

Deixe uma Resposta

Preencha os seus detalhes abaixo ou clique num ícone para iniciar sessão:

Logótipo da WordPress.com

Está a comentar usando a sua conta WordPress.com Terminar Sessão / Alterar )

Imagem do Twitter

Está a comentar usando a sua conta Twitter Terminar Sessão / Alterar )

Facebook photo

Está a comentar usando a sua conta Facebook Terminar Sessão / Alterar )

Google+ photo

Está a comentar usando a sua conta Google+ Terminar Sessão / Alterar )

Connecting to %s

%d bloggers like this: