Sei sulla pagina 1di 16

Consultas dinmicas e typesafe em JPA 2.

Pgina 1

Portugus (Brasil)

Conecte-se (ou Registrar)

Itens Tcnicos

Downloads e Trials

Comunidade

Consultas dinmicas e typesafe em JPA 2.0


Como a Criteria API constri consultas dinmicas e reduz as falhas de tempo de execuo Pinaki Poddar, Senior Software Engineer, IBM Resumo: Uma consulta de objetos persistentes Java typesafe se um compilador puder verific-la quanto correo sinttica. A verso 2.0 da API de persistncia Java (JPA) introduz a Criteria API, que oferece o poder das consultas typesafe para aplicativos Java pela primeira vez e oferece um mecanismo para construir consultas de forma dinmica no tempo de execuo. Este artigo descreve como escrever consultas dinmicas, typesafe utilizando a Criteria API e a API de metamodelo diretamente associada. Data: 26/Out/2009 Nvel: Avanado Atividade: 3240 visualizaes Comentrios: 0 (Incluir comentrios) Mdia de classificao (baseada em 3 votos) A comunidade de desenvolvedores Java deu as boas-vindas JPA desde sua introduo em 2006. A prxima atualizao importante da especificao verso 2.0 (JSR 317) ser concluda no final de 2009 (consulte Recursos). Um dos principais recursos introduzidos na JPA 2.0 a Criteria API, que traz um recurso exclusivo para a linguagem Java: uma forma de desenvolver consultas que um compilador Java possa verificar quanto correo no momento da compilao. A Criteria API tambm inclui mecanismos para construir consultas de forma dinmica no tempo de execuo. Este artigo apresenta a Criteria API e o conceito de metamodelo diretamente associado. Voc saber como utilizar a Criteria API para desenvolver consultas que um compilador Java possa verificar quanto correo para reduzir erros de tempo de execuo, em contraste com as consultas baseadas em cadeias de caracteres da Java Persistence Query Language (JPQL). E atravs de consultas de exemplo que utilizam funes de banco de dados ou comparam uma instncia de modelo, demonstrarei o poder agregado da mecnica programtica de construo de consulta comparada com consultas JPQL que utilizam uma gramtica predefinida. O artigo supe que voc tenha familiaridade bsica da programao em linguagem Java e uso comum de JPA como EntityManagerFactory ou EntityManager . O que h de errado com a consulta JPQL? A JPA 1.0 introduziu a JPQL, uma linguagem poderosa de consulta considerada como a principal razo da popularidade da JPA. Entretanto, a JPQL sendo uma linguagem de consulta baseada em cadeia de caracteres com uma gramtica definida tem algumas limitaes. Para compreender uma das principais limitaes, considere o simples fragmento de cdigo na Listagem 1, que executa uma consulta JPQL para selecionar a lista de Pessoas maiores de 20 anos: Listagem 1. Uma consulta simples (e errada) JPQL
EntityManager String jpql = Query query = List result = em = ...; "select p from Person where p.age > 20"; em.createQuery(jpql); query.getResultList();

Esse exemplo bsico mostra os seguintes aspectos principais do modelo de execuo de consulta na JPA 1.0: Uma consulta JPQL especificada como uma Cadeia de caractere (linha 2). O EntityManager a fbrica que constri uma instncia executvel de consulta dada uma cadeia de caractere JPQL (linha 3). O resultado da execuo de consulta consiste nos elementos de uma java.util.List no tipificado. Mas este exemplo simples tem um erro srio. Efetivamente, o cdigo compilar tranquilamente, mas falhar no tempo de execuo porque a cadeia de caractere de consulta JPQL est sintaticamente incorreta. A sintaxe correta para a segunda linha da Listagem 1 :
String jpql = "select p from Person p where p.age > 20";

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 2

Infelizmente, o compilador Java no tem como detectar tal erro. O erro ser encontrado no tempo de execuo, na linha 3 ou na linha 4 (dependendo se o provedor de JPA analisa uma cadeia de caracteres JPQL de acordo com a gramtica JPQL durante a construo ou execuo da consulta). Como uma consulta typesafe ajuda? Uma das principais vantagens da Criteria API que ela probe a construo de consultas sintaticamente incorretas. A Listagem 2 reescreve a consulta JPQL da Listagem 1 utilizando a interface CriteriaQuery : Listagem 2. Etapas bsicas de escrita de uma CriteriaQuery
EntityManager em = ... QueryBuilder qb = em.getQueryBuilder(); CriteriaQuery<Person> c = qb.createQuery(Person.class); Root<Person> p = c.from(Person.class); Predicate condition = qb.gt(p.get(Person_.age), 20); c.where(condition); TypedQuery<Person> q = em.createQuery(c); List<Person> result = q.getResultList();

Listagem 2 ilustra as estruturas principais da Criteria API e demonstra seu uso bsico: A linha 1 obtm uma instncia EntityManager atravs de um de vrios meios. Na linha 2, o EntityManager cria uma instncia do QueryBuilder. QueryBuilder o factory para o CriteriaQuery . Na linha 3, o factory QueryBuilder constri uma instncia do CriteriaQuery . Um CriteriaQuery genericamente tipificado. O argumento de tipo genrico declara o tipo de resultado que essa CriteriaQuery retornar na execuo. possvel fornecer vrios tipos de argumentos de tipo de resultado desde uma entidade persistente como a Person.class at uma de forma mais livre como a Object[] ao construir uma CriteriaQuery . Na linha 4, as expresses de consulta so definidas na instncia CriteriaQuery . As expresses de consulta so as unidades de ncleo ou ns montados em uma rvore para especificar uma CriteriaQuery . A figura 1 mostra a hierarquia das expresses de consulta definidas na Criteria API:

Figura 1. Hierarquia de interface das expresses de consulta

Para comear, a CriteriaQuery definida para consultar a partir de Person.class. Como resultado, uma instncia Root<Person> p retornada. Root uma expresso de consulta que denota a extenso de uma entidade persistente. Root<T> essencialmente diz: "Avalie esta

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 3

consulta atravs de todas as instncias do tipo T." semelhante clusula FROM de uma consulta JPQL ou SQL. Observe tambm que Root<Person> tipificado genericamente. (Na verdade, toda expresso .) O argumento de tipo o tipo de valor que a expresso avalia. Portanto, Root<Person> denota uma expresso que avalia para Person.class. A linha 5 constri um Predicado . Um predicado outra forma comum de expresso de consulta que avalia quanto a verdadeiro ou falso. Um predicado construdo pelo QueryBuilder, que o factory no apenas para a CriteriaQuery , como tambm para as expresses de consulta. O QueryBuilder tem mtodos de API para construir todos os tipos de expresses de consulta suportados na gramtica tradicional JPQL, e mais alguns. Na listagem 2, o QueryBuilder usado para construir uma expresso que avalia se o valor de seu primeiro argumento de expresso numericamente maior que o valor do segundo argumento. A assinatura do mtodo :
Predicate gt(Expression<? extends Number> x, Number y);

Essa assinatura do mtodo um timo exemplo de como uma linguagem fortemente tipificado como a linguagem Java pode ser criteriosamente usada para definir uma API que permita expressar o que correto e proibir o que no . A assinatura do mtodo especifica que possvel comparar uma expresso cujo valor um Nmero somente com outro Nmero (e no, por exemplo, com uma Cadeia de caracteres ):
Predicate condition = qb.gt(p.get(Person_.age), 20);

Mas h mais na linha 5. Observe o primeiro argumento de entrada qb.gt() do mtodo: p.get(Person_.age), onde p a expresso Root<Person> obtida anteriormente. p.get(Person_.age) uma expresso de caminho. Uma expresso de caminho o resultado da navegao de uma expresso de raiz via um ou mais atributo(s) persistente(s). Portanto, p.get(Person_.age) denota uma expresso de caminho ao navegar da expresso de raiz p pelo atributo de age da Person. Voc pode imaginar qual a Person_.age . Por enquanto, suponha que uma forma de denotar o atributo de age da Person. Eu elaborarei sobre o significado de Person_.age quando discutir sobre a nova API metamodelo introduzida na JPA 2.0. Como mencionei anteriormente, cada expresso de consulta genericamente tipificada para denotar o tipo de valor que a expresso avalia. A expresso de caminho p.get(Person_.age) avalia um Nmero inteiro se o atributo age na Person.class for declarado como do tipo Integer (ou int ). Como a segurana do tipo inerente API, o compilador em si aumentar um erro para uma comparao sem sentido, como:
Predicate condition = qb.gt(p.get(Person_.age, "xyz"));

A linha 6 define o predicado na CriteriaQuery como a clusula WHERE. Na linha 7, o EntityManager cria uma consulta executvel dada uma entrada CriteriaQuery . Isso semelhante construo de uma consulta executvel dada uma cadeia de caractere JPQL como entrada. Mas porque a entrada CriteriaQuery carrega tipo mais rico de informaes, o resultado uma TypedQuery que uma extenso da familiar javax.persistence.Query. A TypedQuery , como o prprio nome sugere, conhece o tipo e retorna como resultado de sua execuo. Ela definida como:
public interface TypedQuery<T> extends Query { List<T> getResultList(); }

Como oposta super interface correspondente no tipificada:


public interface Query { List getResultList(); }

Naturalmente, o resultado da TypedQuery tem o mesmo tipo de Person.class especificado durante a construo da entrada CriteriaQuery por um QueryBuilder (linha 3). Na linha 8, as informaes do tipo carregado por toda parte mostram sua vantagem quando a consulta finalmente executada para obter uma lista de resultados. O resultado uma lista tipificada de Persons que poupa o desenvolvedor do trabalho de um cast extra (e frequentemente feio) (alm de minimizar o risco de erro de ClassCastException no tempo de execuo) ao iterar atravs dos elementos resultantes. Para resumir os aspectos bsicos do exemplo simples na Listagem 2: uma rvore de ns de expresso de consulta utilizada para especificar clusulas de consulta como FROM, WHERE e ORDER BY em uma linguagem tradicional de consulta baseada em cadeia de caracteres. A figura 2 mostra as clusulas relacionadas a uma consulta:
CriteriaQuery

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 4

Figura 2. CriteriaQuery encapsula as clusulas de uma consulta tradicional

As expresses de consulta so tipificadas genericamente. Alguns exemplos tpicos so: Root<T>, equivalente clusula DE. Predicado , que avalia um valor booleano de verdadeiro ou falso. (Na verdade, declarada como Predicado da interface estende Expresso <Booleana>.) Path<T>, que denota um atributo persistente navegado a partir de uma expresso de Raiz<?>. Root<T> um Path<T> especial sem pai. QueryBuilder o factory para o CriteriaQuery e expresses de consulta de todos os tipos.
CriteriaQuery

transferida para uma consulta executvel com a informao do seu tipo preservada para que os elementos da lista selecionada possam ser acessados sem qualquer moldagem do tempo de execuo.

Metamodelo de um domnio persistente A discusso da Listagem 2 aponta uma construo incomum: Person_.age , que uma designao para o atributo persistente de age da Person. A listagem 2 utiliza Person_.age para formar uma expresso de caminho que navega de uma expresso Root<Person> p por p.get(Person_.age). Person_.age um campo pblico esttico na classe Person_ e Person_ a classe de metamodelo cannica, esttica, instanciada correspondente classe original de entidade Person. Uma classe de metamodelo descreve as meta-informaes de uma classe persistente. Uma classe de metamodelo cannica se a classe descrever as meta-informaes de uma entidade persistente da forma exata estipulada pela especificao JPA 2.0. Uma classe de metamodelo cannica esttica no mesmo sentido que todos os seus membros variveis so declarados estticos (e pblicos ). Person_.age um desses membros variveis estticos. A classe cannica instanciada gerando um Person_.java concreto no nvel de cdigo de origem no momento do desenvolvimento. Atravs de tal instanciao, possvel referir-se aos atributos persistentes de Person no momento da compilao e no no tempo de execuo, de forma fortemente tipificada. Essa classe Pessoa_ metamodelo um meio alternativo de fazer referncia meta informao de Person. Essa alternativa semelhante muito usada (alguns diriam at, abusada) API Java Reflection, mas com uma principal diferena conceitual. possvel usar a reflexo para obter meta informao sobre uma instncia java.lang.Class, mas a meta informao Person.class no pode ser referida de forma que um compilador possa verificar. Por exemplo, utilizando reflexo, se faria referncia ao campo chamado age na Person.class com:
Field field = Person.class.getField("age");

Entretanto, essa tcnica carrega o fardo de uma limitao semelhante observada no caso da consulta JPQL baseada em cadeia de caracteres da Listagem 1. O compilador fica feliz com essa parte de cdigo, mas no pode verificar se ele funcionar. O cdigo pode falhar no momento da execuo se incluir at mesmo um simples erro de digitao. A reflexo no funcionar para o que a consulta typesafe da JPA 2.0 pretende alcanar. Uma API de consulta typesafe deve ativar seu cdigo para referir-se ao atributo persistente chamado age em uma classe Person de forma que um compilador possa verificar no momento da compilao. A soluo oferecida pela JPA 2.0 a capacidade de instanciar uma classe metamodelo chamada Person_, que corresponda Person expondo os mesmos atributos persistentes estatisticamente.

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 5

Qualquer discusso sobre meta ou meta-meta informaes normalmente causa sonolncia. Portanto, apresentarei um exemplo concreto de uma classe metamodelo para uma classe de entidade familiar Plain Old Java Object (POJO) domain.Person, demonstrada na Listagem 3: Listagem 3. Entidade persistente simples
package domain; @Entity public class Person { @Id private long ssn; private string name; private int age; // public gettter/setter methods public String getName() {...} }

Esta uma definio tpica de um POJO, com anotaes como @Entity ou @Id que habilitam um provedor JPA a gerenciar instncias dessa classe como entidades persistentes. A classe cannica metamodelo esttica correspondente de domain.Person demonstrada na Listagem 4: Listagem 4. Metamodelo cannica para uma entidade simples
package domain; import javax.persistence.metamodel.SingularAttribute; @javax.persistence.metamodel.StaticMetamodel(domain.Person.class) public class Person_ { public static volatile SingularAttribute<Person,Long> ssn; public static volatile SingularAttribute<Person,String> name; public static volatile SingularAttribute<Person,Integer> age; }

A classe metamodelo declara cada atributo persistente da entidade original domain.Person como um campo pblico esttico do tipo SingularAttribute<Person,?>. Utilizando essa classe metamodelo Person_ , posso me referir ao atributo persistente do domain.Person chamado idade no via API de Reflexo, mas como referncia direta ao campo esttico Person_.age no momento da compilao. O compilador pode ento forar a verificao de tipo com base no tipo declarado de atributo chamado idade. J citei um exemplo de tal restrio: QueryBuilder.gt(p.get(Person_.age), "xyz") causar um erro do compilador porque ele pode determinar a partir da assinatura de QueryBuilder.gt(..) e tipo de Person_.age que a idade da pessoa um campo numrico e no pode ser comparado com uma Cadeia de caracteres . Alguns outros pontos a observar so: O campo metamodelo Person_.age declarado como sendo do tipo javax.persistence.metamodel.SingularAttribute. SingularAttribute uma das interfaces definidas na API metamodelo JPA, a qual descreverei na prxima seo. Os argumentos do tipo genrico de uma SingularAttribute<Person, Integer> denotam a classe que declara o atributo persistente original e o tipo de atributo persistente em si. A classe metamodelo anotada como @StaticMetamodel(domain.Person.class) para design-la como uma classe metamodelo correspondente entidade original persistente domain.Person. A API metamodelo Eu defini uma classe metamodelo como uma descrio de uma classe de entidade persistente. Exatamente como a API de Reflexo precisa de outras interfaces como java.lang.reflect.Field ou java.lang.reflect.Method para descrever os constituintes da java.lang.Class, a API metamodelo JPA tambm precisa de outras interfaces, como SingularAttribute , PluralAttribute, para descrever os tipos de uma classe metamodelo e seus atributos. A figura 3 mostra as interfaces definidas na API metamodelo para descrever tipos:

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 6

Figura 3. Hierarquia de interface para tipos persistentes na API metamodelo

A figura 4 mostra as interfaces definidas na API metamodelo para descrever atributos: Figura 4. Hierarquia de interface para atributos persistentes na API metamodelo

As interfaces da API metamodelo JPA so mais especializadas do que as da API de Reflexo Java. Sua melhor distino necessria para expressar as ricas meta-informaes sobre persistncia. Por exemplo, a API de Reflexo Java representa todos os tipos Java java.lang.Class. Isto , nenhuma distino especial feita via definies separadas entre conceitos como classe, classe abstrata e uma interface. claro que possvel perguntar a uma Class se ela uma interface ou se abstrata , mas isso no o mesmo que representar o conceito de interface de forma diferente de uma classe abstrata via duas definies separadas. A API de Reflexo Java foi introduzida na concepo da linguagem Java (e foi um conceito pioneiro na poca para uma linguagem comum de programao de finalidade geral), mas a conscientizao sobre o uso e o poder dos sistemas fortemente tipificados progrediu ao longo dos anos. A API metamodelo JPA utiliza esse poder para apresentar forte tipificao para entidades persistentes. Por exemplo, as entidades persistentes so semanticamente diferenciadas como MappedSuperClass , Entidade e Embeddable . Antes da JPA 2.0, essa distino semntica era representada atravs de anotaes correspondentes no nvel da classe na definio de classe persistente. O metamodelo JPA descreve trs interfaces separadas MappedSuperclassType , EntityType e EmbeddableType no pacote javax.persistence.metamodel para levar o foco sobre as especialidades semnticas. De forma semelhante, os atributos persistentes so diferenciados no nvel da definio de tipo atravs de interfaces como SingularAttribute , CollectionAttribute e MapAttribute. Com exceo da descrio esttica, essas interfaces metamodelo especializadas tm vantagens prticas que ajudam a construir consultas typesafe e a reduzir a chance de erros no tempo de execuo. Algumas dessas vantagens foram mostradas nos exemplos anteriores, e mais ser mostrado quando eu descrever exemplos de junes utilizando a CriteriaQuery . Escopo de tempo de execuo

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 7

Em termos gerais, possvel traar alguns paralelos entre interfaces tradicionais da API de Reflexo Java e as interfaces javax.persistence.metamodel especializadas para descrever a persistncia de metadados. Para estender a analogia, um conceito equivalente de escopo de tempo de execuo necessrio para interfaces metamodelo. As instncias java.lang.Class tm o escopo definido pelo java.lang.ClassLoader no tempo de execuo. Um conjunto de instncias de classe Java que fazem referncia uma outra deve ser definido sob o escopo de um ClassLoader. Os limites definidos so severos ou fechados no sentido de que se uma classe A definida sob o escopo de um ClassLoader L tentar fazer referncia a uma classe B, que no esteja sob o escopo do ClassLoader L, o resultado um temido ClassNotFoundException ou NoClassDef FoundError (e normalmente noites em claro para um desenvolvedor ou implementador para ambientes com mltiplos ClassLoaders). Essa noo de escopo de tempo de execuo como um conjunto restrito de classes mutuamente referenciadas capturado na JPA 1.0 como uma unidade de persistncia. O escopo de uma unidade de persistncia em termos de suas entidades persistentes enumerado na clusula <classe> de um arquivo META-INF/persistence.xml. Na JPA 2.0, o escopo disponibilizado ao desenvolvedor no tempo de execuo atravs da interface javax.persistence.metamodel.Metamodel . A interface metamodelo a portadora de todas as entidades persistentes conhecidas para uma unidade especfica de persistncia, conforme ilustrado na Figura 5: Figura 5. Interface metamodelo que contm os tipos em uma unidade de persistncia

Essa interface deixa os elementos do metamodelo serem acessados por sua classe de entidade persistente correspondente. Por exemplo, para obter uma referncia para os metadados persistentes para uma entidade persistente Pessoa, possvel escrever:
EntityManagerFactory emf = ...; Metamodel metamodel = emf.getMetamodel(); EntityType<Person> pClass = metamodel.entity(Person.class);

Isso anlogo, com estilo e idiomas levemente diferentes, para obter uma Classe por seu nome via ClassLoader:
ClassLoader classloader = Thread.currentThread().getContextClassLoader(); Class<?> clazz = classloader.loadClass("domain.Person");

EntityType<Person> pode ser navegado no tempo de execuo para obter os atributos persistentes declarados na entidade Pessoa. Se o aplicativo invoca um mtodo na pClass como pClass.getSingularAttribute("age", Integer.class), ele retornar uma instncia SingularAttribute<Person, Integer> que efetivamente a mesma que o membro esttico Person_.age da classe metamodelo cannica

instanciada. Essencialmente, o atributo persistente a que o aplicativo pode se referir no tempo de execuo via a API metamodelo disponibilizado para um compilador Java por instanciao da classe metamodelo esttica cannica Person_ . Com exceo da resoluo de uma entidade persistente para seus elementos metamodelo correspondentes, a API metamodelo tambm permite acesso a todas as classes metamodelo conhecidas (Metamodel.getManagedTypes()) ou acesso a uma classe metamodelo atravs de suas informaes especficas de persistncia por exemplo embeddable(Address.class), que retorna uma instncia EmbeddableType<Address> que uma subinterface do ManagedType<>. Na JPA, as meta-informaes sobre um POJO so adicionalmente atribudas com meta informaes especficas persistentes como se uma classe integrada ou quais campos so utilizados como chave primria com anotaes no nvel do cdigo de origem (ou descritores XML). As meta-informaes persistentes entram em duas amplas categorias: para persistncia (como @Entity) e mapeamento (como @Table). Na JPA 2.0, o metamodelo captura os metadados apenas para anotaes de persistncia no para anotao de mapeamento. Portanto, com a verso atual da API metamodelo, possvel saber quais campos so persistentes, mas no possvel descobrir para quais colunas do banco de dados elas so mapeadas. Cannica x no-cannica Embora uma especificao JPA 2.0 estipule a forma exata de uma classe metamodelo esttica cannica (inclusive nome totalmente qualificado da classe metamodelo e os nomes de seus campos estticos), plenamente possvel tambm para um aplicativo escrever essas classes metamodelo. Se o desenvolvedor do aplicativo escrever as classes metamodelo, elas so chamadas de metamodelo no-cannicas. Atualmente, a especificao para metamodelo no-cannico no muito detalhada e o suporte para metamodelo no-cannico pode no ser portvel entre os provedores de JPA. Voc pode ter notado que os campos pblicos estticos so apenas declarados no metamodelo cannico, mas no inicializado. A declarao possibilita fazer referncia a esses campos durante o desenvolvimento de uma CriteriaQuery . Mas eles precisam http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/ 31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 8

receber um valor para serem teis no tempo de execuo. Embora seja responsabilidade do provedor JPA atribuir valores a esses campos para metamodelo cannico, no estendida garantia semelhante para metamodelo no-cannico. Os aplicativos que utilizam metamodelo nocannico devem depender de mecanismos especficos do fornecedor ou projetar sua prpria mecnica para inicializar os valores de campo para atributos de metamodelo no tempo de execuo.

Gerao de cdigo e usabilidade


A gerao automtica de cdigo de origem normalmente causa desconfiana. O caso de cdigo de origem gerado para metamodelo cnico traz algumas preocupaes. As classes geradas so utilizadas durante do desenvolvimento e outras partes do cdigo que constroem a CriteriaQuery fazem referncia direta a elas no momento da compilao, deixando algumas dvidas quanto usabilidade: Os arquivos de cdigo de origem deveriam ser gerados no mesmo diretrio da fonte original, em um diretrio separado ou relacionado ao diretrio de sada? Os arquivos de cdigo fonte deveriam ser verificados em um sistema de gerenciamento de configurao controlado por verso? Como a correspondncia entre uma definio original de entidade Pessoa e seu metamodelo cannico Person_ deve ser mantida? Por exemplo, e se Person.java for editado para adicionar um outro atributo persistente ou refatorado para renomear um atributo persistente? As respostas a essas perguntas no so definitivas at o momento. Processamento de anotao e gerao de metamodelo Naturalmente, se voc tiver muitas entidades persistentes, no ficar inclinado a escrever classes metamodelo. Espera-se que o provedor de persistncia gere essas classes metamodelo para voc. A especificao no ordena tal instalao ou a mecnica de gerao, mas um entendimento implcito entre os provedores JPA que eles geraro o metamodelo cannico utilizando a instalao de Processador de Anotao integrada no compilador Java 6. O Apache OpenJPA oferece um utilitrio para gerar essas classes metamodelo implicitamente ao compilar o cdigo de origem para entidades persistentes ou invocando explicitamente um script. Antes do Java 6, uma ferramenta de processador de anotao chamada apt era disponibilizada e muito utilizada mas com o Java 6, o acoplamento entre o compilador e o Processador de Anotao definido como parte do padro. O processo de gerao dessas classes metamodelo no OpenJPA como seu provedor de persistncia simples como compilar a entidade POJO com as bibliotecas de classe OpenJPA no caminho de classe do compilador:
$ javac domain/Person.java

A classe metamodelo cannica Person_ ser gerada, escrita no mesmo diretrio de origem que Person.java e compilada como efeito colateral dessa compilao. Escrevendo consultas de forma typesafe At aqui, estabeleci os componentes da CriteriaQuery e suas classes metamodelo associadas. Agora mostrarei como desenvolver algumas consultas com a Criteria API. Expresses funcionais As expresses funcionais aplicam uma funo a um ou mais argumentos de entrada para criar uma nova expresso. O tipo de expresso funcional depende da natureza da funo e tipo de seus argumentos. Os argumentos de entrada em si podem ser expresses ou valores literais. As regras de verificao de tipo do compilador, juntamente com a assinatura da API regulam o que constitui entrada legtima. Considere uma expresso de argumento nico que aplica mdia em sua expresso de entrada. A listagem 5 mostra a CriteriaQuery para selecionar o saldo mdio de todas as Contas: Listagem 5. Expresso funcional na CriteriaQuery
CriteriaQuery<Double> c = cb.createQuery(Double.class); Root<Account> a = c.from(Account.class); c.select(cb.avg(a.get(Account_.balance)));

Uma consulta JPQL equivalente seria:


Cadeia de caractere jpql = "select avg(a.balance) from Account a";

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 9

Na Listagem 5, o factory QueryBuilder (representado pela varivel cb) cria uma expresso avg() e utiliza a expresso na clusula select() da consulta. A expresso de consulta um bloco de construo que pode ser montado para definir o predicado de seleo final para a consulta. O exemplo na Listagem 6 mostra uma expresso de Caminho criada atravs da navegao para o saldo da Conta, e ento a expresso de Caminho utilizada como expresso de entrada em algumas expresses funcionais binrias greaterThan() e lessThan() ambas resultando em uma expresso booleana ou simplesmente um predicado. Os predicados so ento combinados via uma operao and() para formar o predicado de seleo final a ser avaliado pela clusula where() da consulta:

API fluente
Como mostra esse exemplo, os mtodos da Criteria API frequentemente retornam o tipo que pode ser usado diretamente em um mtodo relacionado, fornecendo assim um estilo popular de programao conhecido como API fluente. Listagem 6. Predicado where() na CriteriaQuery
CriteriaQuery<Account> c = cb.createQuery(Account.class); Root<Account> account = c.from(Account.class); Path<Integer> balance = account.get(Account_.balance); c.where(cb.and (cb.greaterThan(balance, 100), cb.lessThan(balance), 200)));

Uma consulta JPQL equivalente seria:


"select a from Account a where a.balance>100 and a.balance<200";

Predicados complexos Certas expresses tais como in() se aplicam a um nmero varivel de expresses. A listagem 7 mostra um exemplo: Listagem 7. Expresso de valor mltiplo na CriteriaQuery
CriteriaQuery<Account> c = cb.createQuery(Account.class); Root<Account> account = c.from(Account.class); Path<Person> owner = account.get(Account_.owner); Path<String> name = owner.get(Person_.name); c.where(cb.in(name).value("X").value("Y").value("Z"));

Este exemplo navega da Account via duas etapas para criar uma expresso de caminho representando o nome do proprietrio da conta. Ento ele cria uma expresso in() com a expresso de caminho como entrada. A expresso in() avalia se sua expresso de entrada se iguala a qualquer um de seu nmero varivel de argumentos. Esses argumentos so especificados atravs do mtodo value() na expresso In<T>, a qual tem a seguinte assinatura de mtodo:
In<T> value(T value);

Note como generalidades do Java so usadas para especificar que uma expresso In<T> pode ser avaliada para associao apenas com valores do tipo T. Como a expresso de caminho representando o nome do proprietrio da Conta do tipo Cadeia de caractere , a nica comparao vlida entre argumentos avaliados quanto Cadeia de caractere , o que pode ser uma expresso literal ou outra que avalia para Cadeia de caractere . Compare a consulta na Listagem 7 com a JPQL equivalente (correta):
"select a from Account a where a.owner.name in ('X','Y','Z')";

Um leve descuido na JPQL no somente deixar de ser detectado pelo compilador, mas tambm produzir um resultado indesejado. Por exemplo:
"select a from Account a where a.owner.name in (X, Y, Z)";

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0 Unindo relacionamentos

Pgina 10

Embora os exemplos na Listagem 6 e Listagem 7 utilizem expresses como blocos construtores, as consultas so baseadas em uma nica entidade e seus atributos. Mas as consultas frequentemente envolvem mais de uma entidade, o que exige que voc una duas ou mais entidades. A CriteriaQuery expressa a unio de duas entidades por expresses de juno tipificadas. Uma expresso de juno tipificada tem dois parmetros de tipo: o tipo que voc est unindo e o tipo de ligao do atributo sendo unido. Por exemplo, se voc deseja consultar os Customer s cujo(s) PurchaseOrder (s) no foram entregues ainda, necessrio expressar isso atravs de uma expresso que una o Customer ao(s) PurchaseOrder s, onde o Customer tenha um atributo persistente chamado orders do tipo java.util.Set<PurchaseOrder>, como demonstrado na Listagem 8: Listagem 8. Unindo um atributo de valor mltiplo
CriteriaQuery<Customer> q = cb.createQuery(Customer.class); Root<Customer> c = q.from(Customer.class); SetJoin<Customer, PurchaseOrder> o = c.join(Customer_.orders);

A expresso de unio criada a partir da expresso de raiz c e o atributo persistente Customer.orders parametrizado pela fonte de unio isso , Customer e o tipo que pode ser ligado do atributo Customer.orders, que PurchaseOrder e no o tipo declarado java.util.Set<PurchaseOrder>. Observe tambm que como o atributo original do tipo java.util.Set , a expresso de unio resultante SetJoin, que uma Juno para um atributo de tipo declarado java.util.Set . De forma semelhante, para outros tipos de atributo persistente de valor mltiplo suportados, a API define CollectionJoin , ListJoin e MapJoin. (A Figura 1 mostra as diversas expresses de juno.) No necessria uma modelagem explcita na terceira linha da Listagem 8 porque CriteriaQuery e a API metamodelo reconhece e distingue os tipos de atributos declarados como java.util.Collection ou List ou Set ou Map por mtodos sobrecarregados para join().
PurchaseOrder (s) no entregues, possvel definir status DELIVERED e negando o predicado como:

As junes so usadas em consultas para formar um predicado na entidade unida. Portanto, se desejar selecionar os Customer s com um ou mais um predicado navegando da expresso unida o via seu atributo de status, comparando-o com o

Predicate p = cb.equal(o.get(PurchaseOrder_.status), Status.DELIVERED) .negate();

Um ponto que merece ateno sobre a criao de uma expresso de juno que toda vez que voc faz a juno de uma expresso, ela retorna uma nova expresso de juno, como demonstrado na Listagem 9: Listagem 9. Cada juno cria uma instncia nica
SetJoin<Customer, PurchaseOrder> o1 = c.join(Customer_.orders); SetJoin<Customer, PurchaseOrder> o2 = c.join(Customer_.orders); assert o1 == o2;

A assero na Listagem 9 para a igualdade de duas expresses de juno a partir da mesma expresso c com o mesmo atributo falhar. Portanto, se uma consulta envolver um predicado para PurchaseOrder s que no so entregues e cujo valor mais que $200, a construo correta deve unir PurchaseOrder com a expresso de raiz Customer apenas uma vez, atribuir a expresso de juno resultante a uma varivel local (equivalente a uma faixa varivel na terminologia JPQL) e utilizar a varivel local na formao do predicado. Utilizando parmetros Revise a consulta JPQL original neste artigo (a correta):
String jpql = "select p from Person p where p.age > 20";

Embora as consultas sejam frequentemente escritas com literais constantes, essa no uma boa prtica. A boa prtica parametrizar uma consulta, o que permite que a consulta seja analisada ou preparada somente uma vez, armazenada em cache e reutilizada. Portanto, uma forma melhor de escrever a consulta usar um parmetro nomeado:
String jpql = "select p from Person p where p.age > :age";

Uma consulta parametrizada liga o valor do parmetro antes da execuo da consulta:


Query query = em.createQuery(jpql).setParameter("age", 20); List result = query.getResultList();

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 11

Em uma consulta JPQL, os parmetros so codificados na cadeia de caractere da consulta como nomeados (precedidos por dois pontos por exemplo, :age ) ou posicional (precedido por um ponto de interrogao por exemplo, ?3). Na CriteriaQuery , os parmetros em si so expresses de consultas. Como qualquer outra expresso, elas so fortemente tipificadas e construdas pelo factory de expresso a saber, QueryBuilder A consulta na Listagem 2, portanto, pode ser parametrizada como demonstrado na Listagem 10: Listagem 10. Usando parmetros em uma CriteriaQuery
ParameterExpression<Integer> age = qb.parameter(Integer.class); Predicate condition = qb.gt(p.get(Person_.age), age); c.where(condition); TypedQuery<Person> q = em.createQuery(c); List<Person> result = q.setParameter(age, 20).getResultList();

Para comparar a utilizao dos parmetros com os da JPQL: a expresso de parmetro criada com informao de tipo explcito para ser um Integer e usada diretamente para ligar um valor de 20 para a consulta executvel. As informaes de tipo extra so sempre teis para reduzir os erros no tempo de execuo, pois probe o parmetro de ser comparado com uma expresso de um tipo incompatvel ou ser ligado a um valor de tipo inadmissvel. Nenhuma forma de segurana no tempo de compilao garantida para os parmetros de uma consulta JPQL. O exemplo na Listagem 10 mostra uma expresso do parmetro no denominada que utilizada diretamente para ligao. Tambm possvel atribuir um nome ao parmetro como segundo argumento durante sua construo. Nesse caso, possvel ligar o valor do parmetro consulta utilizando esse nome. O que no possvel, entretanto, o uso de parmetros posicionais. A posio integrar em uma cadeia de caractere (linear) de consulta JPQL faz algum sentido de forma intuitiva, mas a noo de uma posio no pode ser levada adiante no contexto da CriteriaQuery , onde o modelo conceitual uma rvore de expresses de consulta. Outro aspecto interessante dos parmetros de consulta JPA que eles no tm valor intrnseco. Um valor ligado a um parmetro no contexto de uma consulta executvel. Portanto, perfeitamente legal criar duas consultas executveis separadas a partir da mesma CriteriaQuery e ligar dois valores inteiros diferentes ao mesmo parmetro para essas consultas executveis. Projetando o resultado Voc viu que o tipo de resultado que uma CriteriaQuery retornar na execuo especificado frente quando uma CriteriaQuery construda por um QueryBuilder. O resultado da consulta especificado como um ou mais termos de projeo. H duas formas de especificar o termo de projeo na interface CriteriaQuery :
CriteriaQuery<T> select(Selection<? extends T> selection); CriteriaQuery<T> multiselect(Selection<?>... selections);

O termo de projeo mais simples e frequentemente utilizado a classe candidata da consulta em si. Pode estar implcita, como demonstrado na Listagem 11. Listagem 11. CriteriaQuery seleciona a extenso do candidato por padro
CriteriaQuery<Account> q = cb.createQuery(Account.class); Root<Account> account = q.from(Account.class); List<Account> accounts = em.createQuery(q).getResultList();

Na Listagem 11, a consulta de Account no especifica explicitamente esse termo de seleo e o mesmo que selecionar explicitamente a classe candidata. A listagem 12 apresenta uma consulta que utiliza um termo explcito de seleo: Listagem 12. CriteriaQuery com termo exclusivo explcito de seleo
CriteriaQuery<Account> q = cb.createQuery(Account.class); Root<Account> account = q.from(Account.class); q.select(account); List<Account> accounts = em.createQuery(q).getResultList();

Quando o resultado projetado da consulta algo diferente da entidade persistente candidata em si, vrias outras construes so disponibilizadas para formar o resultado da consulta. Essas construes so disponibilizadas na interface QueryBuilder, como demonstrado na Listagem 13:

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 12

Listagem 13. Mtodos para formar o resultado da consulta


<Y> CompoundSelection<Y> construct(Class<Y> result, Selection<?>... terms); CompoundSelection<Object[]> array(Selection<?>... terms); CompoundSelection<Tuple> tuple(Selection<?>... terms);

Os mtodos na Listagem 13 constroem um termo de projeo composto de outras expresses selecionveis. O mtodo construct() cria uma instncia de determinado argumento de classe e invoca um construtor com valores dos termos de seleo de entrada. Por exemplo, se CustomerDetails uma entidade no-persistente tiver um construtor que toma argumentos String e int , uma CriteriaQuery pode ento retornar os CustomerDetails como resultado criando instncias a partir do nome e idade do Customer selecionado de uma entidade persistente de instncias, como demonstrado na Listagem 14: Listagem 14. Formando o resultado da consulta em instncias de uma classe por construct()
CriteriaQuery<CustomerDetails> q = cb.createQuery(CustomerDetails.class); Root<Customer> c = q.from(Customer.class); q.select(cb.construct(CustomerDetails.class, c.get(Customer_.name), c.get(Customer_.age));

Os termos mltiplos de projeo tambm podem ser combinados em um termo composto que representa um Object[] ou Tuple. A listagem 15 mostra como compactar o resultado em um Object[]: Listagem 15. Formando o resultado da consulta em um Object[]
CriteriaQuery<Object[]> q = cb.createQuery(Object[].class); Root<Customer> c = q.from(Customer.class); q.select(cb.array(c.get(Customer_.name), c.get(Customer_.age)); List<Object[]> result = em.createQuery(q).getResultList();

Essa consulta retorna uma lista de resultados na qual cada elemento um Object[] de comprimento 2, o elemento de array zero o nome do Customer e o primeiro elemento a idade do Customer .
Tuple uma interface definida por JPA para denotar uma linha de dados. Um Tuple conceitualmente uma lista de TupleElements em que TupleElement a unidade atmica e a raiz de todas as expresses de consulta. Os valores contidos em um Tuple podem ser acessados por um ndice de nmero inteiro baseado em 0 (semelhante ao resultado JDBC familiar), um nome alternativo do TupleElement ou diretamente pelo TupleElement. A listagem 16 mostra como compactar o resultado em um Tuple:

Listagem 16. Formando o resultado da consulta em Tuple


CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Customer> c = q.from(Customer.class); TupleElement<String> tname = c.get(Customer_.name).alias("name"); q.select(cb.tuple(tname, c.get(Customer_.age).alias("age"); List<Tuple> result = em.createQuery(q).getResultList(); String name = result.get(0).get(name); String age = result.get(0).get(1);

Limitaes no aninhamento
Teoricamente possvel compor formas complexas de resultados aninhando termos como um Tuple cujos elementos so Object[]s ou Tuples. Entretanto, a especificao JPA 2.0 probe tal aninhamento. Os termos de entrada de um multiselect() no podem ser um array ou termo composto de valor tupla. Os nicos termos compostos permitidos como argumentos multiselect() so os criados pelo mtodo construct() (que essencialmente representa um elemento nico). Entretanto, o OpenJPA no coloca qualquer restrio no aninhamento de um termo de seleo composto dentro de outro. Essa consulta retorna uma lista de resultados onde cada um de seus elementos um Tuple. Cada tupla, por sua vez, carrega dois elementos acessveis pelo ndice ou pelo alias, se houver, dos TupleElements individuais ou diretamente pelo TupleElement. Dois pontos que merecem ateno na Listagem 16 so o uso de alias(), que uma forma de anexar um nome a qualquer expresso de consulta (criando uma nova cpia como efeito colateral) e um mtodo createTupleQuery() no QueryBuilder, que simplesmente uma alternativa ao createQuery(Tuple.class).

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 13

O comportamento desses mtodos individuais de formao de resultado e o que especificado como argumento de tipo de resultado da CriteriaQuery durante a construo combinado na semntica do mtodo multiselect(). Esse mtodo interpreta seus termos de entrada com base no tipo de resultado da CriteriaQuery para chegar forma do resultado. Para construir instncias CustomerDetails como na Listagem 14 usando multiselect(), necessrio especificar a CriteriaQuery a ser do tipo CustomerDetails e simplesmente invocar multiselect() com os termos que iro compor o construtor CustomerDetails , como demonstrado na Listagem 17: Listagem 17. multiselect() interpreta termos baseado no tipo de resultado
CriteriaQuery<CustomerDetails> q = cb.createQuery(CustomerDetails.class); Root<Customer> c = q.from(Customer.class); q.multiselect(c.get(Customer_.name), c.get(Customer_.age));

Como o tipo de resultado CustomerDetails , o multiselect() interpreta seus termos de projeo de argumento como o argumento construtor para o CustomerDetails . Se a consulta for especificada para retornar um Tuple, o mtodo multiselect() com os mesmos argumentos exatos que criariam instncias Tuple, como mostrado na Listagem 18: Listagem 18. Criando instncias Tuple com multiselect()
CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Customer> c = q.from(Customer.class); q.multiselect(c.get(Customer_.name), c.get(Customer_.age));

O comportamento do multiselect() fica mais interessante com o Object como tipo de resultado ou se nenhum argumento de tipo for especificado. Em tais casos, se multiselect() for usado com um nico termo de entrada, o valor de retorno o termo selecionado. Mas se multiselect() contiver mais de um termo de entrada, o resultado um Object[]. Recursos avanados At aqui, enfatizei principalmente a natureza fortemente tipificada da Criteria API e o fato de que ela ajuda a minimizar os erros sintticos que causam lentido nas consultas JPQL baseadas em cadeia de caractere. A Criteria API tambm um mecanismo para construir consultas programaticamente e portanto normalmente referida como uma API dinmica de consulta. O poder de uma API de construo de consulta programvel limitado somente pela criatividade do seu usurio. Apresentarei quatro exemplos: Utilizao de uma verso fraca tipificada da API para construir consultas dinmicas Utilizao de uma funo suportada por banco de dados como expresso de consulta para estender a gramtica Edio de uma consulta para funcionalidade de busca dentro dos resultados Consulta por exemplo um padro familiar popularizado pela comunidade de banco de dados de objeto Tipificao fraca e construo dinmica de consulta A forte verificao de tipo da Criteria API baseada na disponibilidade das classes metamodelo instanciadas no momento do desenvolvimento. Entretanto, para alguns casos de uso, as entidades a serem selecionadas podem ser determinadas no tempo de execuo. Para suportar tal uso, os mtodos da Criteria API oferecem uma verso paralela na qual os atributos persistentes so referenciados por seus nomes (semelhante API de Reflexo Java) ao invs de por referncia aos atributos metamodelo estticos instanciados. Essa verso paralela da API pode suportar construo de consulta verdadeiramente dinmica sacrificando a verificao do tipo no tempo de compilao. A Listagem 19 reescreve um exemplo na Listagem 6 utilizando a verso tipificada fraca: Listagem 19. Consulta tipificada fraca
Class<Account> cls = Class.forName("domain.Account"); Metamodel model = em.getMetamodel(); EntityType<Account> entity = model.entity(cls); CriteriaQuery<Account> c = cb.createQuery(cls); Root<Account> account = c.from(entity); Path<Integer> balance = account.<Integer>get("balance"); c.where(cb.and (cb.greaterThan(balance, 100), cb.lessThan(balance), 200)));

A API tipificada fraca, entretanto, no pode retornar expresses tipificadas genericamente, gerando um aviso de compilador para um modelo no verificado. Uma forma de livrar-se dessas mensagens de aviso incmodas usar uma instalao relativamente rara de elementos genricos Java: invocao de mtodo parametrizado, como demonstrado na invocao da Listagem 19 do mtodo get() para obter uma expresso de caminho.

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0 Expresses extensveis de armazenamento de dados

Pgina 14

Uma vantagem distinta de um mecanismo de construo dinmica de consulta que a gramtica extensvel. Por exemplo, possvel utilizar o mtodo function() na interface QueryBuilder para criar uma expresso suportada pelo banco de dados:
<T> Expression<T> function(String name, Class<T> type, Expression<?>...args);

O mtodo function() cria uma expresso do nome dado e zero ou mais expresses de entrada. A expresso de function() avalia o tipo dado. Isso permite que um aplicativo crie uma consulta que avalie uma funo de banco de dados. Por exemplo, o banco de dados MySQL suporta uma funo CURRENT_USER() que retorna a combinao nome de usurio e nome de host como uma sequencia codificada UTF-8 para a conta MySQL que o servidor utilizou para autenticar o cliente atual. Um aplicativo pode utilizar a funo CURRENT_USER(), que no toma nenhum argumento, em uma CriteriaQuery , como demonstrado na Listagem 20: Listagem 20. Usando parmetros em uma CriteriaQuery
CriteriaQuery<Tuple> q = cb.createTupleQuery(); Root<Customer> c = q.from(Customer.class); Expression<String> currentUser = cb.function("CURRENT_USER", String.class, (Expression<?>[])null); q.multiselect(currentUser, c.get(Customer_.balanceOwed));

Observe que uma consulta equivalente simplesmente no possvel para expressar em JPQL, pois tem uma gramtica definida com um nmero fixo de expresses suportadas. Uma API dinmica no estritamente limitada por um conjunto fixo de expresses. Consulta editvel Uma CriteriaQuery pode ser editado programaticamente. As clusulas da consulta como seus termos de seleo, predicado de seleo em uma clusula WHERE e termos de pedido em uma clusula ORDER BY podem todos ser modificados. Esse recurso de edio pode ser usado em uma instalao do tipo "procura em resultado", por onde um predicado de consulta adicionalmente refinado em etapas sucessivas adicionando mais restries. O exemplo na Listagem 21 cria uma consulta que solicita seu resultado por nome e ento edita a consulta para classificar tambm pelo CEP: Listagem 21. Editando uma CriteriaQuery
CriteriaQuery<Person> c = cb.createQuery(Person.class); Root<Person> p = c.from(Person.class); c.orderBy(cb.asc(p.get(Person_.name))); List<Person> result = em.createQuery(c).getResultList(); // start editing List<Order> orders = c.getOrderList(); List<Order> newOrders = new ArrayList<Order>(orders); newOrders.add(cb.desc(p.get(Person_.zipcode))); c.orderBy(newOrders); List<Person> result2 = em.createQuery(c).getResultList();

Avaliao na memria em OpenJPA


Com os recursos estendidos do OpenJPA, o exemplo de procura nos resultados da Listagem 21 pode se tornar ainda mais eficiente avaliando a consulta editada na memria. Esse exemplo impe que o resultado da consulta editada seja um subconjunto restrito do resultado original. Como o OpenJPA pode avaliar uma consulta na memria quando uma coleo candidata especificada, a nica modificao necessria que a ltima linha da Listagem 21 fornea o resultado da consulta original:
List<Person> result2 = em.createQuery(c).setCandidateCollection(result).getResultList();

Os mtodos setter na CriteriaQuery select(), where() ou orderBy() apagam os valores anteriores e os substituem com novos argumentos. A lista retornada pelos mtodos getter correspondentes, tais como getOrderList() no est ativa isto , adicionar ou remover elementos na lista retornada no modifica o CriteriaQuery; alm disso, alguns fornecedores podem at retornar uma lista imutvel de proibir uso inadvertido. Portanto, uma boa prtica copiar a lista retornada em uma nova lista antes de adicionar ou remover novas expresses. Consulta por exemplo

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0

Pgina 15

Outra facilidade til em uma API de consulta dinmica que ela pode suportar consulta por exemplo com relativa facilidade. A consulta por exemplo (desenvolvida pela IBM Research em 1970) normalmente citada como um exemplo primrio da usabilidade de software pelo usurio final. A ideia de consulta por exemplo que ao invs de especificar os predicados exatos para uma consulta, uma instncia de modelo apresentada. Dada a instncia de modelo, uma conjuno de predicados onde cada um deles uma comparao para um valor de atributo noanulvel, no-padro da instncia de modelo criada. A execuo dessa consulta avalia o predicado para encontrar todas as instncias que correspondem instncia de modelo. A consulta por exemplo foi considerada para incluso na especificao JPA 2.0 no est includa. OpenJPA suporta esse estilo de consulta atravs de sua interface estendida OpenJPAQueryBuilder , como demonstrado na Listagem 22 : Listagem 22. Consulta por exemplo utilizando extenso do OpenJPA da CriteriaQuery
CriteriaQuery<Employee> q = cb.createQuery(Employee.class); Employee example = new Employee(); example.setSalary(10000); example.setRating(1); q.where(cb.qbe(q.from(Employee.class), example);

Como mostra esse exemplo, a extenso do OpenJPA da interface QueryBuilder suporta a seguinte expresso:
public <T> Predicate qbe(From<?, T> from, T template);

Essa expresso produz uma conjuno de predicados baseados nos valores de atributo de determinada instncia de modelo. Por exemplo, essa consulta encontrar todos os Employee s com um salrio de 10000 e classificao de 1. A comparao pode ser adicionalmente controlada pela especificao de uma lista opcional de atributos a serem excludos da comparao e estilo de comparao para atributos avaliados por String. (Consulte os Recursos para um link para o Javadoc para extenses do OpenJPA CriteriaQuery .) Concluso Este artigo apresentou a nova Criteria API no JPA 2.0 como mecanismo para desenvolver consultas dinmicas, typesafe na linguagem Java. Uma construda no tempo de execuo como uma rvore de expresses de consulta fortemente tipificada que usam o artigo conforme ilustrado em uma srie de exemplos de cdigo.
CriteriaQuery

Este artigo tambm estabelece o papel crtico da nova API metamodelo e mostra como as classes metamodelo instanciadas permitem que o compilador verifique a correo das consultas, evitando assim erros de tempo de execuo causados por consultas JPQL sintaticamente incorretas. Alm de reforar a correo sinttica, as facilidades JPA 2.0 para construo programtica de consultas pode levar ao uso mais potente, como consulta por exemplo, utilizando funes de banco de dados e, espero muitos outros usos inovadores dessas poderosas novas APIs que os leitores deste artigo podero inventar. Agradecimentos Agradeo a Rainer Kwesi Schweigkoffer pela cuidadosa reviso deste artigo e valiosas sugestes, e tambm os membros do Grupo Especializado na JPA 2.0 por explicar os pontos mais delicados desta poderosa API. Agradeo tambm Fay Wang por sua contribuio e Larry Kestila e Jeremy Bauer pelo apoio durante o desenvolvimento da Criteria API para OpenJPA.

Recursos Aprender JSR 317 - Java Persistence 2.0 (este link reside fora de ibm.com): possvel encontrar mais documentos sobre a especificao JPA 2.0 no web site Java Community Process. Apache OpenJPA (este link reside fora de ibm.com): Saiba mais sobre o projeto de persistncia Apache Java. OpenJPA Javadoc for CriteriaQuery (este link reside fora de ibm.com): Veja o Javadoc para o pacote org.apache.openjpa.persistence.criteria . LIQUidFORM (este link reside fora de ibm.com): Saiba sobre uma abordagem alternativa para disponibilizar meta-informaes para a verificao de tipo Java. Navegue at a livraria de tecnologia para ver livros sobre estes e outros tpicos tcnicos.

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Consultas dinmicas e typesafe em JPA 2.0 developerWorks Java technology zone: Encontre centenas de artigos sobre cada aspecto da programao Java. Discutir Envolva-se na comunidade My developerWorks. Sobre o autor

Pgina 16

Pinaki Poddar works in middleware technology with an emphasis on object persistence. He is a member of the Expert Group for the Java Persistence API (JSR 317) specification and a committer for the Apache OpenJPA project. In a past life, he contributed to the building of component-oriented integration middleware for a global investment bank and a medical image-processing platform for the healthcare industry. For his doctoral thesis, he developed an indigenous, neural-network-based automatic speech-recognition system.
Imprimir esta pgina Compartilhe esta pgina Siga o developerWorks

Itens Tcnicos
Information Management Lotus Rational Tivoli WebSphere Biblioteca Tcnica Feeds Java technologia Linux Open source

Downloads e Trials

Comunidade
Fruns Grupos Blogs Wikis Arquivos Termos de uso Relatar abuso

Sobre o developerWorks
Ajuda e comentrios sobre o site Contate os editores

Recursos relacionados
IBM Academic Initiative IBM PartnerWorld Industry network

Saiba mais...
Cloud computing Segmentos de Indstrias

Saiba mais... IBM


Solues Software IBM Servios Suporte & Downloads Suporte & Downloads (Documentao) Redbooks (Ingls) Privacidade Acessibilidade (Ingls)

http://www.ibm.com/developerworks/br/java/library/j-typesafejpa/

31/08/2011 19:21:38

Potrebbero piacerti anche