Académique Documents
Professionnel Documents
Culture Documents
18 de junho de 2012
Sumrio Sobre a K19 Seguro Treinamento Termo de Uso Cursos 1 Introduo 1.1 Persistncia . . . . . . . . . . 1.2 Congurao . . . . . . . . . 1.3 Mapeamento . . . . . . . . . 1.4 Gerando o banco . . . . . . 1.5 Exerccios de Fixao . . . . 1.6 Exerccios Complementares 1.7 Manipulando entidades . . 1.8 Exerccios de Fixao . . . . 1.9 Exerccios Complementares
i 1 2 3 4 1 1 1 2 3 3 4 5 7 8 9 9 10 10 11 11 12 12 13 14 15 16 18
i
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
Mapeamento 2.1 Entidades . . . . . . . . . . . . . . . . . . . . . 2.2 Denindo Restries . . . . . . . . . . . . . . 2.3 Gerando chaves primrias automaticamente 2.4 Mapeamento Automtico . . . . . . . . . . . 2.5 Objetos Grandes (LOB) . . . . . . . . . . . . . 2.6 Data e Hora . . . . . . . . . . . . . . . . . . . . 2.7 Dados Transientes . . . . . . . . . . . . . . . . 2.8 Field Access e Property Access . . . . . . . . . 2.9 Exerccios de Fixao . . . . . . . . . . . . . . 2.10 Enums . . . . . . . . . . . . . . . . . . . . . . . 2.11 Colees . . . . . . . . . . . . . . . . . . . . . 2.12 Relacionamentos . . . . . . . . . . . . . . . .
www.k19.com.br
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
. . . . . . . . . . . .
S UMRIO
ii
2.13 2.14 2.15 2.16 2.17 2.18 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 3
One to One . . . . . . . . . . . . Exerccios de Fixao . . . . . . One to Many . . . . . . . . . . . Exerccios de Fixao . . . . . . Many to One . . . . . . . . . . . Exerccios de Fixao . . . . . . Many to Many . . . . . . . . . . Exerccios de Fixao . . . . . . Relacionamentos Bidirecionais Exerccios de Fixao . . . . . . Objetos Embutidos . . . . . . . Exerccios de Fixao . . . . . . Herana . . . . . . . . . . . . . . Exerccios de Fixao . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
. . . . . . . . . . . . . .
18 20 22 23 25 26 28 29 31 32 34 36 37 41 43 43 43 45 46 50 53 56 56 57 57 58 59 61 62 63 66 68 69 70 71 72 72 73 75 75 75 76 77 81 84 88 88 88
Entity Manager 3.1 Estados . . . . . . . . . . . . . . . . . . . . . . . . 3.2 Sincronizao com o Banco de Dados . . . . . . 3.3 Transies . . . . . . . . . . . . . . . . . . . . . . 3.4 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.5 LAZY e EAGER . . . . . . . . . . . . . . . . . . . . 3.6 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.7 Caching . . . . . . . . . . . . . . . . . . . . . . . . 3.8 Persistence Context ou Cache de Primeiro Nvel 3.9 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.10 Shared Cache ou Cache de Segundo Nvel . . . . 3.11 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.12 Cascade . . . . . . . . . . . . . . . . . . . . . . . . 3.13 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.14 Remoo de Objetos rfos . . . . . . . . . . . . 3.15 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.16 Callbacks . . . . . . . . . . . . . . . . . . . . . . . 3.17 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.18 Concorrncia . . . . . . . . . . . . . . . . . . . . . 3.19 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.20 Locking Otimista . . . . . . . . . . . . . . . . . . . 3.21 Exerccios de Fixao . . . . . . . . . . . . . . . . 3.22 Locking Pessimista . . . . . . . . . . . . . . . . . 3.23 Exerccios de Fixao . . . . . . . . . . . . . . . . JPQL 4.1 Consultas Dinmicas 4.2 Named Query . . . . 4.3 Parmetros . . . . . . 4.4 Exerccios de Fixao 4.5 Tipos de Resultado . 4.6 Exerccios de Fixao 4.7 Paginao . . . . . . . 4.8 Exerccios de Fixao 4.9 O Problema do N + 1
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
ii
www.k19.com.br
iii
S UMRIO
Exerccios de Fixao . . . . . . . . . . Operaes em Lote (Bulk Operations) Exerccios de Fixao . . . . . . . . . . Operadores . . . . . . . . . . . . . . . . Exemplos . . . . . . . . . . . . . . . . . Referncias . . . . . . . . . . . . . . . . Consultas Nativas . . . . . . . . . . . . Exerccios de Fixao . . . . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
. . . . . . . .
89 90 91 93 97 98 98 98 101 101 101 102 105 105 107 109 109 109 112 114 114 114 116 117 118 119 123 123 124 124 124 125 129 129 130 130
Criteria 5.1 Necessidade . . . . . . . . . 5.2 Estrutura Geral . . . . . . . . 5.3 Exerccios de Fixao . . . . 5.4 Exerccios Complementares 5.5 Tipos de Resultados . . . . . 5.6 Exerccios de Fixao . . . . 5.7 Filtros e Predicados . . . . . 5.8 Exerccios de Fixao . . . . 5.9 Lista de Predicados . . . . . 5.10 Funes . . . . . . . . . . . . 5.11 Ordenao . . . . . . . . . . 5.12 Subqueries . . . . . . . . . . 5.13 Exemplos . . . . . . . . . . . 5.14 O Problema do N + 1 . . . . 5.15 Exerccios de Fixao . . . . 5.16 Metamodel . . . . . . . . . . 5.17 Exerccios de Fixao . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
A Hibernate Search A.1 Congurao . . . . . A.2 Mapeamento . . . . . A.3 Indexao . . . . . . . A.4 Busca . . . . . . . . . A.5 Exerccios de Fixao
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
C Bean Validation e Hibernate Validator 135 C.1 Regras de Validao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135 C.2 Processando as Validaes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 C.3 Exerccios de Fixao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 D Mapeamento com XML D.1 Entidades . . . . . . . . . . . . . . . . . . . . . D.2 Denindo Restries . . . . . . . . . . . . . . D.3 Gerando chaves primrias automaticamente D.4 Mapeamento Automtico . . . . . . . . . . .
www.k19.com.br
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
. . . .
S UMRIO
iv
D.5 D.6 D.7 D.8 D.9 D.10 D.11 D.12 D.13 D.14 D.15 D.16 D.17 D.18 D.19 D.20 D.21 D.22 D.23 D.24 D.25 D.26 E
Objetos Grandes (LOB) . . . . . Data e Hora . . . . . . . . . . . . Dados Transientes . . . . . . . . Field Access e Property Access . Exerccios de Fixao . . . . . . Enums . . . . . . . . . . . . . . . Colees . . . . . . . . . . . . . Relacionamentos . . . . . . . . One to One . . . . . . . . . . . . Exerccios de Fixao . . . . . . One to Many . . . . . . . . . . . Exerccios de Fixao . . . . . . Many to One . . . . . . . . . . . Exerccios de Fixao . . . . . . Many to Many . . . . . . . . . . Exerccios de Fixao . . . . . . Relacionamentos Bidirecionais Exerccios de Fixao . . . . . . Objetos Embutidos . . . . . . . Exerccios de Fixao . . . . . . Herana . . . . . . . . . . . . . . Exerccios de Fixao . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . . . . . . .
145 145 146 147 147 149 150 152 153 155 156 159 160 163 164 166 167 170 172 174 176 180 183
Respostas
iv
www.k19.com.br
S UMRIO
Sobre a K19
A K19 uma empresa especializada na capacitao de desenvolvedores de software. Sua equipe composta por prossionais formados em Cincia da Computao pela Universidade de So Paulo (USP) e que possuem vasta experincia em treinamento de prossionais para rea de TI. O principal objetivo da K19 oferecer treinamentos de mxima qualidade e relacionados s principais tecnologias utilizadas pelas empresas. Atravs desses treinamentos, seus alunos se tornam capacitados para atuar no mercado de trabalho. Visando a mxima qualidade, a K19 mantm as suas apostilas em constante renovao e melhoria, oferece instalaes fsicas apropriadas para o ensino e seus instrutores esto sempre atualizados didtica e tecnicamente.
www.k19.com.br
S UMRIO
Seguro Treinamento
Na K19 o aluno faz o curso quantas vezes quiser! Comprometida com o aprendizado e com a satisfao dos seus alunos, a K19 a nica que possui o Seguro Treinamento. Ao contratar um curso, o aluno poder refaz-lo quantas vezes desejar mediante a disponibilidade de vagas e pagamento da franquia do Seguro Treinamento. As vagas no preenchidas at um dia antes do incio de uma turma da K19 sero destinadas ao alunos que desejam utilizar o Seguro Treinamento. O valor da franquia para utilizar o Seguro Treinamento 10% do valor total do curso.
www.k19.com.br
S UMRIO
Termo de Uso
Termo de Uso
Todo o contedo desta apostila propriedade da K19 Treinamentos. A apostila pode ser utilizada livremente para estudo pessoal . Alm disso, este material didtico pode ser utilizado como material de apoio em cursos de ensino superior desde que a instituio correspondente seja reconhecida pelo MEC (Ministrio da Educao) e que a K19 seja citada explicitamente como proprietria do material. proibida qualquer utilizao desse material que no se enquadre nas condies acima sem o prvio consentimento formal, por escrito, da K19 Treinamentos. O uso indevido est sujeito s medidas legais cabveis.
www.k19.com.br
S UMRIO
TR
www.k19.com.br/cursos
www.k19.com.br
CAPTULO
I NTRODUO
Persistncia
Aplicaes corporativas manipulam dados em grande quantidade. Na maioria dos casos, esses dados so armazenados em bancos de dados relacionais, pois os principais sistemas gerenciadores de bancos de dados do mercado utilizam o modelo relacional. Por outro lado, hoje em dia, as aplicaes corporativas costumam ser desenvolvidas com linguagens orientadas a objetos. Como o modelo relacional e o modelo orientado a objetos diferem no modo de estruturar os dados, uma transformao deve ocorrer toda vez que alguma informao trafegar da aplicao para o banco de dados ou vice-versa. Essa transformao no simples, pois os dois modelos so bem diferentes. No contexto das aplicaes Java, para facilitar o processo de transformao dos dados que trafegam entre as aplicaes e os bancos de dados, podemos utilizar algumas ferramentas de persistncia como o Hibernate ou o EclipseLink. Essas ferramentas funcionam como intermedirios entre as aplicaes e os bancos de dados, automatizando diversos processos importantes relacionados persistncia dos dados. Elas so chamadas de ferramentas ORM (Object Relational Mapping). Com o intuito de facilitar a utilizao dessas ferramentas e torn-las compatveis com os outros recursos da plataforma Java, elas so padronizadas pela especicao Java Persistence API (JPA). Veremos, nesse captulo, os passos principais para utilizar uma implementao da JPA. Em particular, utilizaremos o Hibernate e o sistema gerenciador de banco de dados MySQL.
Congurao
Antes de comear a utilizar o Hibernate, necessrio baixar do site ocial o bundle que inclui os jars do hibernate e todas as suas dependncias. Neste curso, utilizaremos a verso 4.1.2. A url do site ocial do Hibernate http://www.hibernate.org/.
Mais Sobre
Veja tambm um artigo da K19 sobre congurao do Hibernate no seguinte endereo http://www.k19.com.br/artigos/configurando-hibernate-com-mysql/.
Para congurar o Hibernate em uma aplicao, devemos criar um arquivo chamado persistence.xml. O contedo desse arquivo contm informaes sobre o banco de dados, como a url de conewww.k19.com.br
I NTRODUO
xo, usurio e senha, alm de dados sobre a implementao JPA que ser utilizada. O arquivo persistence.xml deve ser salvo em uma pasta chamada META-INF, que deve estar no classpath da aplicao. Veja abaixo um exemplo de congurao para o persistence.xml:
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 < persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K19 - PU " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " usuario " / > < property name = " javax . persistence . jdbc . password " value = " senha " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / k19_bd " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML 1.1: persistence.xml
Mapeamento
Um dos principais objetivos dos frameworks ORM estabelecer o mapeamento entre os conceitos do modelo orientado a objetos e os conceitos do modelo relacional. Este mapeamento pode ser denido atravs de xml ou de maneira mais prtica com anotaes Java. Quando utilizamos anotaes, evitamos a criao de extensos arquivos em xml. A seguir, veremos as principais anotaes Java de mapeamento do JPA. Essas anotaes esto no pacote javax.persistence.
@Entity a principal anotao do JPA. Ela deve aparecer antes do nome de uma classe e deve ser denida em todas as classes que tero objetos persistidos no banco de dados. As classes anotadas com @Entity so mapeadas para tabelas. Por conveno, as tabelas possuem os mesmos nomes das classes. Mas, podemos alterar esse comportamento utilizando a anotao @Table. Os atributos declarados em uma classe anotada com @Entity so mapeados para colunas na tabela correspondente classe. Outra vez, por conveno, as colunas possuem os mesmos nomes dos atributos. E novamente, podemos alterar esse padro utilizando para isso a anotao @Column. @Id utilizada para indicar qual atributo de uma classe anotada com @Entity ser mapeado para a chave primria da tabela correspondente classe. Geralmente o atributo anotado com @Id do tipo Long.
2
www.k19.com.br
I NTRODUO
@GeneratedValue Geralmente vem acompanhado da anotao @Id. Serve para indicar que o valor de um atributo que compe uma chave primria deve ser gerado pelo banco no momento em que um novo registro inserido.
Gerando o banco
Uma das vantagens de utilizar uma implementao JPA que ela capaz de gerar as tabelas no banco de dados. Ela faz isso de acordo com as anotaes colocadas nas classes e as informaes presentes no arquivo persistence.xml. As tabelas so geradas atravs de um mtodo esttico da classe Persistence, o createEntityManagerFactory(string persistenceUnit). O parmetro persistenceUnit permite escolher, pelo nome, uma unidade de persistncia denida no persistence.xml.
1 Persistence . createEntityManagerFactory ( " K19 - PU " ) ;
Cdigo Java 1.1: Inicializando uma unidade de persistncia.
Exerccios de Fixao
Para apresentar os conceitos bsicos de JPA, implementaremos parte de um sistema de gerenciamento de uma livraria. Primeiramente, crie um projeto no Eclipse chamado K19-JPA2-Hibernate.
1 2 3
Entre na pasta K19-Arquivos/hibernate-release-4.1.2.Final/lib da rea de Trabalho e copie os jars da pasta required e da pasta jpa para a pasta lib do projeto K19-JPA2-Hibernate.
4
Crie uma pasta chamada META-INF dentro da pasta src do projeto K19-JPA2-Hibernate.
Crie o arquivo de conguraes persistence.xml na pasta META-INF. Para no ter de digitar todo o cdigo, copie o modelo persistence.xml da pasta K19-Arquivos/modelos da sua rea de Trabalho. Altere esse modelo de acordo com o cdigo abaixo.
1 2 3 4 5 6 7 8 9 1 11 12 < persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_livraria_pu " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / >
www.k19.com.br
I NTRODUO
13 14 15 16 17 18 19 2 21 22 < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_livraria_bd " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML 1.2: persistence.xml
Crie uma classe para modelar as editoras da nossa livraria e acrescente as anotaes necessrias para fazer o mapeamento. Essas anotaes devem ser importadas do pacote javax.persistence. Adicione essa classe em um pacote chamado br.com.k19.modelo.
8
1 2 3 4 5 6 7 8 9 1 11
@Entity public class Editora { @Id @GeneratedValue private Long id ; private String nome ; private String email ; // GETTERS E SETTERS }
Cdigo Java 1.2: Editora.java
9 Apague a base dados K21_livraria_bd se ela existir atravs do MySQL Workbench. Pea orientao do instrutor se for necessrio.
Crie a base dados K21_livraria_bd atravs do MySQL Workbench. Pea orientao do instrutor se for necessrio.
10
Gere as tabelas usando o mtodo createEntityManagerFactory() da classe Persistence. Para isso, crie uma classe com mtodo main em um pacote chamado br.com.k19.testes no projeto K19JPA2-Hibernate. Obs: As classes devem ser importadas do pacote javax.persistence.
11
1 2 3 4 5 6 7 8
public class GeraTabelas { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_livraria_pu " ) ; factory . close () ; } }
Cdigo Java 1.3: GeraTabelas.java
Execute e verique atravs do MySQL Workbench se a tabela Editora foi criada corretamente.
Exerccios Complementares
Na pacote br.com.k19.modelo do projeto K19-JPA2-Hibernate, crie uma classe chamada Autor para modelar um autor. Essa classe deve conter dois atributos: um para armazenar o id do autor e
1
www.k19.com.br
I NTRODUO
Manipulando entidades
Para manipular as entidades da nossa aplicao, devemos utilizar um EntityManager que obtido atravs de uma EntityManagerFactory.
1 2 3 4 EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K19 - PU " ) ; EntityManager manager = factory . createEntityManager () ;
Cdigo Java 1.6: Obtendo um Entity Manager
Persistindo
Para armazenar as informaes de um objeto no banco de dados, devemos utilizar o mtodo
persist() do EntityManager.
1 2 3 4 5 Editora novaEditora = new Editora () ; novaEditora . setNome ( " K19 - Livros " ) novaEditora . setEmail ( " contato@k19 . com . br " ) ; manager . persist ( novaEditora ) ;
Cdigo Java 1.7: Associando um objeto a um Entity Manager.
Buscando
Para obter um objeto que contenha informaes do banco de dados, podemos utilizar os mtodos find() ou getReference() do EntityManager.
1 2 Editora editora1 = manager . find ( Editora . class , 1 L ) ; Editora editora2 = manager . getReference ( Editora . class , 2 L ) ;
Cdigo Java 1.8: Buscando objetos.
H uma diferena entre esses mtodos de busca. O mtodo find() recupera os dados desejados imediatamente. J o mtodo getReference() posterga essa tarefa at a primeira chamada de um mtodo get no objeto desejado.
Removendo
Para remover um registro correspondente a um objeto, podemos utilizar o mtodo remove() do
EntityManager.
www.k19.com.br
I NTRODUO
1 2 Editora editora = manager . find ( Editora . class , 1 L ) ; manager . remove ( editora ) ;
Cdigo Java 1.9: Marcando um objeto para ser removido.
Atualizando
Para alterar os dados de um registro correspondente a um objeto, podemos utilizar os prprios mtodos setters desse objeto.
1 2 Editora editora = manager . find ( Editora . class , 1 L ) ; editora . setNome ( " K19 - Livros e Publicaes " ) ;
Cdigo Java 1.10: Alterando o contedo de um objeto.
Listando
Para obter uma listagem com todos os objetos referentes aos registros de uma tabela, podemos utilizar a linguagem de consulta do JPA, a JPQL. Essa linguagem muito parecida com a linguagem SQL. A vantagem da JPQL em relao linguagem SQL que a sintaxe a mesma para bancos de dados diferentes.
1 2 Query query = manager . createQuery ( " SELECT e FROM Editora e " ) ; List < Editora > editoras = query . getResultList () ;
Cdigo Java 1.11: Denindo e executando uma consulta JPQL.
Transaes
As modicaes realizadas nos objetos administrados por um EntityManager so mantidas em memria. Em certos momentos, necessrio sincronizar os dados da memria com os dados do banco de dados. Essa sincronizao deve ser realizada atravs de uma transao JPA criada pelo EntityManager que administra os objetos que desejamos sincronizar. Para abrir uma transao utilizamos o mtodo begin().
1 manager . getTransaction () . begin () ;
Cdigo Java 1.12: Abrindo uma transao.
Com a transao aberta, podemos sincronizar os dados com o banco atravs dos mtodos flush() (parcialmente) ou commit() (denitivamente).
1 2 3 4 5 Editora editora = manager . find ( Editora . class , 1 L ) ; editora . setNome ( " K19 - Livros e Publicaes " ) ; manager . getTransaction () . begin () ; manager . flush () ;
Cdigo Java 1.13: Sincronizando parcialmente uma transao.
www.k19.com.br
7
1 2 3 4 5 Editora editora = manager . find ( Editora . class , 1 L ) ; editora . setNome ( " K19 - Livros e Publicaes " ) ; manager . getTransaction () . begin () ; manager . getTransaction () . commit () ;
Cdigo Java 1.14: Sincronizando denitivamente uma transao
I NTRODUO
Exerccios de Fixao
12 No pacote br.com.k19.testes do projeto K19-JPA2-Hibernate, crie um teste para inserir editoras no banco de dados.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26
public class InsereEditoraComJPA { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_livraria_pu " ) ; EntityManager manager = factory . createEntityManager () ; Editora novaEditora = new Editora () ; Scanner entrada = new Scanner ( System . in ) ; System . out . println ( " Digite o nome da editora : " ) ; novaEditora . setNome ( entrada . nextLine () ) ; System . out . println ( " Digite o email da editora : " ) ; novaEditora . setEmail ( entrada . nextLine () ) ; manager . persist ( novaEditora ) ; manager . getTransaction () . begin () ; manager . getTransaction () . commit () ; factory . close () ; } }
Cdigo Java 1.15: InsereEditoraComJPA.java
No pacote br.com.k19.testes do projeto K19-JPA2-Hibernate, crie um teste para listar as editoras inseridas no banco de dados. No cdigo abaixo, a interface Query deve ser importada do pacote javax.persistence e a interface List do pacote java.util.
13
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
public class ListaEditorasComJPA { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_livraria_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " SELECT e FROM Editora e " ) ; List < Editora > editoras = query . getResultList () ; for ( Editora e : editoras ) { System . out . println ( " EDITORA : " + e . getNome () + " - " + e . getEmail () ) ; } }
www.k19.com.br
I NTRODUO
16 }
Cdigo Java 1.16: ListaEditorasComJPA.java
Exerccios Complementares
No pacote br.com.k19.testes do projeto K19-JPA2-Hibernate, crie um teste para inserir autores no banco de dados.
3
No pacote br.com.k19.testes do projeto K19-JPA2-Hibernate, crie um teste para listar os autores inseridos no banco de dados.
4
www.k19.com.br
CAPTULO
Cdigo Java 2.1: Pessoa.java Cdigo Java 2.2: Pessoa.java
M APEAMENTO
O mapeamento objeto-relacional o corao do Hibernate e das outras implementaes de JPA. Ele dene quais transformaes devem ser realizadas nos dados para que essas informaes possam navegar da aplicao para o banco de dados ou do banco de dados para a aplicao. Em particular, o mapeamento determina como a ferramenta ORM far consultas complexas envolvendo mais do que uma tabela.
Entidades
As classes da nossa aplicao que devem ser mapeadas para tabelas do banco de dados so anotadas com @Entity. Cada instncia de uma classe anotada com @Entity deve possuir um identicador nico. Em geral, esse identicador um atributo numrico que deve ser anotado com @Id.
1 2 3 4 5 @Entity class Pessoa { @Id private Long id ; }
Por conveno, a classe Pessoa ser mapeada para uma tabela com o mesmo nome (Pessoa). O atributo id ser mapeado para uma coluna com o mesmo nome (id) na tabela Pessoa. As anotaes @Table e @Column podem ser usadas para personalizar os nomes das tabelas e das colunas. A coluna correspondente ao atributo id ser denida como chave primria da tabela Pessoa devido a presena da anotao @Id.
1 2 3 4 5 6 7 @Entity @Table ( name = " tbl_pessoas " ) class Pessoa { @Id @Column ( name = " col_id " ) private Long id ; }
www.k19.com.br
M APEAMENTO
10
(a)
(b)
Figura 2.1: Tabelas correspondentes classe Pessoa. Em (a), os nomes da tabela e da coluna so padres. Em (b), esses nomes so personalizados.
Denindo Restries
Podemos denir algumas restries para os atributos das nossas entidades atravs das propriedades da anotao @Column. Veja as principais propriedades abaixo:
Limita a quantidade de caracteres de uma string Determina se o campo pode possuir valores null ou no Determina se uma coluna pode ter valores repetidos ou no Determina a quantidade de dgitos de um nmero decimal a serem armazenadas Determina a quantidade de casas decimais de um nmero decimal
Tabela 2.1: Algumas propriedades da anotao @Column
No exemplo a seguir, associamos trs restries ao atributo nome da classe Pessoa. O nome deve possuir no mximo 30 caracteres, no pode ser nulo e duas pessoas no podem ter o mesmo nome. Alm disso, denimos que a altura das pessoas ser representada por um nmero de trs dgitos, sendo dois deles referentes s casas decimais.
1 2 3 4 5 6 7 8 9 1 11 @Entity class Pessoa { @Id private Long id ; @Column ( length =3 , nullable = false , unique = true ) private String nome ; @Column ( precision =3 , scale =2) private BigDecimal altura ; }
Cdigo Java 2.3: Pessoa.java
11
M APEAMENTO
@GeneratedValue para que o banco gere os valores de uma chave primria simples e numrica automaticamente.
1 2 3 4 5 6 @Entity class Pessoa { @Id @GeneratedValue private Long id ; }
Cdigo Java 2.4: Pessoa.java
Mapeamento Automtico
Cada banco possui o seu prprio conjunto de tipos de dados. Para que as informaes possam navegar da aplicao para o banco e vice-e-versa, os tipos do Java devem ser mapeados para tipos apropriados do banco de dados. Alguns tipos do Java so mapeados automaticamente para tipos correspondentes do banco de dados. Eis uma lista dos tipos que so mapeados automaticamente:
Tipos primitivos (byte, short, char, int, long, oat, double e boolean) Classes Wrappers (Byte, Short, Character, Integer, Long, Float, Double e Boolean) String BigInteger e BigDecimal java.util.Date e java.util.Calendar java.sql.Date, java.sql.Time e java.sql.Timestamp Array de byte ou char Enums Serializables
11
M APEAMENTO
1 2 3 4 5 6 7 8 9 @Entity class Pessoa { @Id @GeneratedValue private Long id ; @Lob private byte [] avatar ; }
Cdigo Java 2.5: Pessoa.java
12
Data e Hora
Comumente, as aplicaes Java utilizam as classes java.util.Date e java.util.Calendar para trabalhar com datas e horas. Essas classes so mapeadas automaticamente para tipos adequados no banco de dados. Portanto, basta declarar os atributos utilizando um desses dois tipos nas classes que sero mapeadas para tabelas.
1 2 3 4 5 6 7 8 @Entity class Pessoa { @Id @GeneratedValue private Long id ; private Calendar nascimento ; }
Cdigo Java 2.6: Pessoa.java
Por padro, quando aplicamos o tipo java.util.Date ou java.util.Calendar, tanto a data quanto a hora sero armazenadas no banco de dados. Para mudar esse comportamento, devemos aplicar a anotao @Temporal escolhendo uma das trs opes abaixo:
TemporalType.DATE: Armazena apenas a data (dia, ms e ano). TemporalType.TIME: Armazena apenas o horrio (hora, minuto e segundo). TemporalType.TIMESTAMP (Padro): Armazena a data e o horrio.
1 2 3 4 5 6 7 8 9
@Entity class Pessoa { @Id @GeneratedValue private Long id ; @Temporal ( TemporalType . DATE ) private Calendar nascimento ; }
Cdigo Java 2.7: Pessoa.java
Dados Transientes
12
www.k19.com.br
13
M APEAMENTO
Eventualmente, no desejamos que alguns atributos de um determinado grupo de objetos sejam persistidos no banco de dados. Nesse caso, devemos aplicar o modicador transient ou a anotao @Transient. No exemplo abaixo, marcamos o atributo idade com a anotao @Transient para que essa informao no seja armazenada no banco de dados. A idade de uma pessoa pode ser deduzida a partir de sua data de nascimento, que j est armazenada no banco.
1 2 3 4 5 6 7 8 9 1 11 12 @Entity class Pessoa { @Id @GeneratedValue private Long id ; @Temporal ( TemporalType . DATE ) private Calendar nascimento ; @Transient private int idade ; }
Cdigo Java 2.8: Pessoa.java
Figura 2.2: Tabela correspondente classe Pessoa. Note que essa tabela no possui nenhuma coluna associada ao atributo idade da classe
Pessoa
13
M APEAMENTO
14
Exerccios de Fixao
Crie um projeto no Eclipse chamado K19-Mapeamento. Copie a pasta lib do projeto K19-JPA2Hibernate para o projeto K19-Mapeamento. Depois adicione os jars dessa pasta no classpath desse novo projeto.
1
Abra o MySQL Workbench e apague a base de dados K21_mapeamento_bd se existir. Depois crie a base de dados K21_mapeamento_bd.
2 3 Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-Mapeamento. Altere o arquivo persistence.xml do projeto K19-Mapeamento, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22
< persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_mapeamento_pu " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_mapeamento_bd " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML 2.1: persistence.xml
Crie uma entidade para modelar os usurios de uma rede social dentro de um pacote chamado
14
www.k19.com.br
15
5
M APEAMENTO
Adicione um usurio no banco de dados. Crie uma classe chamada AdicionaUsuario em um pacote chamado br.com.k19.testes no projeto K19-Mapeamento.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 public class AdicionaUsuario { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Usuario usuario = new Usuario () ; usuario . setEmail ( " contato@k19 . com . br " ) ; usuario . setDataDeCadastro ( Calendar . getInstance () ) ; manager . persist ( usuario ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 2.10: AdicionaUsuario.java
6 Abra o MySQL Workbench e observe as propriedades da tabela Usuario da base de dados K21_mapeamento_bd.
Enums
Por padro, os tipos enumerados de JAVA so mapeados para colunas numricas inteiras no banco de dados. Cada elemento de um Enum associado a um nmero inteiro. Essa associao baseada na ordem em que os elementos do Enum so declarados. O primeiro elemento ser associado ao valor 0, o segundo ser associado ao valor 1 e assim por diante. Considere o exemplo a seguir.
1 2 3 4 5 @Entity public enum Periodo { MATUTINO , NOTURNO }
Cdigo Java 2.11: Periodo.java
1 2 3 4 5 6 7 8
@Entity public class Turma { @Id @GeneratedValue private Long id ; private Periodo periodo ; }
Cdigo Java 2.12: Turma.java
O Enum Periodo possui dois elementos: MATUTINO e NOTURNO. O elemento MATUTINO ser associado ao valor 0 e o elemento NOTURNO ser associado ao valor 1.
www.k19.com.br
15
M APEAMENTO
16
A tabela correspondente classe Turma possuir um campo chamado periodo. Nos registros correspondentes s turmas de perodo matutino, esse campo possuir o valor 0. J nos registros correspondentes s turmas de perodo noturno, esse campo possuir o valor 1. Imagine que um novo perodo adicionado, digamos, o perodo vespertino. Nesse caso, o Enum
Os valores j armazenados no banco de dados poderiam estar incorretos. Por exemplo, antes dessa modicao, o campo periodo das turmas noturnas deveria armazenar o valor 1. Aps essa modicao, o valor correto passa a ser 2. Assim, os valores do campo periodo da tabela Turma devem ser atualizados de acordo. No entanto, essa atualizao no automtica, e deve ser feita manualmente. Para evitar esse problema, podemos fazer com que os elementos de um Enum sejam associados a uma string ao invs de um nmero inteiro. Isso pode ser feito com o uso da anotao @Enumerated. Observe o exemplo abaixo.
1 2 3 4 5 6 7 8 9 @Entity public class Turma { @Id @GeneratedValue private Long id ; @Enumerated ( EnumType . STRING ) private Periodo periodo ; }
Cdigo Java 2.14: Turma.java
Nesse exemplo, os elementos MATUTINO, VESPERTINO e NOTURNO do Enum Periodo sero associados s strings "MATUTINO", "VESPERTINO" e "NOTURNO", respectivamente.
Colees
Considere um sistema que controla o cadastro dos funcionrios de uma empresa. Esses funcionrios so modelados pela seguinte classe.
1 2 3 4 5 6 7 8 @Entity public class Funcionario { @Id @GeneratedValue private Long id ; private String nome ; }
Cdigo Java 2.15: Funcionario.java
16
www.k19.com.br
17
M APEAMENTO
Devemos tambm registrar os telefones de contato dos funcionrios, sendo que cada funcionrio pode ter um ou mais telefones. Em Java, seria razovel utilizar colees para armazenar os telefones dos funcionrios. Veja o exemplo abaixo.
1 2 3 4 5 6 7 8 9 1 11 @Entity public class Funcionario { @Id @GeneratedValue private Long id ; private String nome ; @ElementCollection private Collection < String > telefones ; }
A anotao @ElementCollection deve ser utilizada para que o mapeamento seja realizado. Nesse exemplo, o banco de dados possuiria uma tabela chamada Funcionario_telefones contendo duas colunas. Uma coluna seria usada para armazenar os identicadores dos funcionrios e a outra para os telefones. Veja uma ilustrao das tabelas do banco de dados na gura abaixo.
A tabela criada para guardar os telefones dos funcionrios tambm pode ter o seu nome personalizado, assim como os nomes de suas colunas. Para isso, devemos aplicar as anotaes @CollectionTable e @Column.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 @Entity public class Funcionario { @Id @GeneratedValue private Long id ; private String nome ; @ElementCollection @CollectionTable ( name = " Telefones_dos_Funcionarios " , joinColumns = @JoinColumn ( name = " func_id " ) ) @Column ( name = " telefone " ) private Collection < String > telefones ; }
www.k19.com.br
17
M APEAMENTO
18
Relacionamentos
Os relacionamentos entre as entidades de um domnio devem ser expressos na modelagem atravs de vnculos entre classes. De acordo com a JPA, podemos denir quatro tipos de relacionamentos de acordo com a cardinalidade. One to One (Um para Um): Por exemplo, um estado governado por apenas um governador e um governador governa apenas um estado.
One to Many (Um para Muitos): Por exemplo, um departamento possui muitos funcionrios e um funcionrio trabalha em apenas em um departamento.
Many to One (Muitos para Um): Por exemplo, um pedido pertence a apenas um cliente e um cliente faz muitos pedidos.
Many to Many (Muitos para Muitos): Por exemplo, um livro possui muitos autores e um autor possui muitos livros.
One to One
Suponha que em nosso domnio existam duas entidades: Estado e Governador. Devemos criar uma classe para cada entidade e aplicar nelas as anotaes bsicas de mapeamento.
18
www.k19.com.br
19
1 2 3 4 5 6 @Entity class Estado { @Id @GeneratedValue private Long id ; }
Cdigo Java 2.18: Estado.java
M APEAMENTO
1 2 3 4 5 6
Como existe um relacionamento entre estados e governadores, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Estado.
1 2 3 4 5 6 7 8 @Entity class Estado { @Id @GeneratedValue private Long id ; private Governador governador ; }
Cdigo Java 2.20: Estado.java
Alm disso, devemos informar ao provedor JPA que o relacionamento que existe entre um estado e um governador do tipo One to One. Fazemos isso aplicando a anotao @OneToOne no atributo que expressa o relacionamento.
1 2 3 4 5 6 7 8 9 @Entity class Estado { @Id @GeneratedValue private Long id ; @OneToOne private Governador governador ; }
Cdigo Java 2.21: Estado.java
No banco de dados, a tabela referente classe Estado possuir uma coluna de relacionamento chamada de join column. Em geral, essa coluna ser denida como uma chave estrangeira associada tabela referente classe Governador. Por padro, o nome da coluna de relacionamento formado pelo nome do atributo que estabelece o relacionamento, seguido pelo caractere _ e pelo nome do atributo que dene a chave primria da entidade alvo. No exemplo de estados e governadores, a join column teria o nome governador_id.
www.k19.com.br
19
M APEAMENTO
20
Podemos alterar o nome padro das join columns aplicando a anotao @JoinColumn, conforme apresentado no exemplo abaixo.
1 2 3 4 5 6 7 8 9 1 @Entity class Estado { @Id @GeneratedValue private Long id ; @OneToOne @JoinColumn ( name = " gov_id " ) private Governador governador ; }
Cdigo Java 2.22: Estado.java
Mais Sobre
Por padro, em um relacionamento One to One, um objeto da primeira entidade no precisa estar necessariamente relacionado a um objeto da segunda entidade. Para exigir que cada objeto da primeira entidade esteja relacionado a um objeto da segunda entidade, devemos usar o atributo optional da anotao OneToOne.
1 2 3 4 5 6 7 8 9 @Entity class Estado { @Id @GeneratedValue private Long id ; @OneToOne ( optional = false ) private Governador governador ; }
Cdigo Java 2.23: Estado.java
Exerccios de Fixao
20
www.k19.com.br
21
M APEAMENTO
1 2 3 4 5 6 7 8 9 1
@Entity public class Governador { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 2.24: Governador.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Estado { @Id @GeneratedValue private Long id ; private String nome ; @OneToOne private Governador governador ; // GETTERS E SETTERS }
Cdigo Java 2.25: Estado.java
Adicione um governador e um estado no banco de dados. Crie uma classe chamada Adiciona-
Abra o MySQL Workbench e observe as propriedades das tabelas Estado e Governador da base
www.k19.com.br
21
M APEAMENTO
22
de dados K21_mapeamento_bd.
One to Many
Suponha que em nosso domnio existam as entidades Departamento e Funcionrio. Criaramos duas classes com as anotaes bsicas de mapeamento.
1 2 3 4 5 6 @Entity class Departamento { @Id @GeneratedValue private Long id ; }
Cdigo Java 2.27: Departamento.java
1 2 3 4 5 6
Como existe um relacionamento entre departamentos e funcionrios, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Departamento. Supondo que um departamento possa ter muitos funcionrios, devemos utilizar uma coleo para expressar esse relacionamento.
1 2 3 4 5 6 7 8 @Entity class Departamento { @Id @GeneratedValue private Long id ; private Collection < Funcionario > funcionarios ; }
Cdigo Java 2.29: Departamento.java
Para informar a cardinalidade do relacionamento entre departamentos e funcionrios, devemos utilizar a anotao @OneToMany na coleo.
1 2 3 4 5 6 7 8 9 @Entity class Departamento { @Id @GeneratedValue private Long id ; @OneToMany private Collection < Funcionario > funcionarios ; }
Cdigo Java 2.30: Departamento.java
No banco de dados, alm das duas tabelas correspondentes s classes Departamento e Funcionario, deve existir uma terceira tabela para relacionar os registros dos departamentos com os registros
22
www.k19.com.br
23
M APEAMENTO
dos funcionrios. Essa terceira tabela chamada de tabela de relacionamento ou join table. Por padro, o nome da join table a concatenao com _ dos nomes das duas entidades. No exemplo de departamentos e funcionrios, o nome do join table seria Departamento_Funcionario. Essa tabela possuir duas colunas vinculadas s entidades que formam o relacionamento. No exemplo, a join table Departamento_Funcionario possuir uma coluna chamada Departamento_id e outra chamada funcionarios_id.
Para personalizar os nomes das colunas da join table e da prpria join table, podemos aplicar a anotao @JoinTable no atributo que dene o relacionamento.
1 2 3 4 5 6 7 8 9 1 11 12 @Entity class Departamento { @Id @GeneratedValue private Long id ; @OneToMany @JoinTable ( name = " DEP_FUNC " , joinColumns = @JoinColumn ( name = " DEP_ID " ) , inverseJoinColumns = @JoinColumn ( name = " FUNC_ID " ) ) private Collection < Funcionario > funcionarios ; }
Cdigo Java 2.31: Departamento.java
Exerccios de Fixao
www.k19.com.br
23
M APEAMENTO
24
1 2 3 4 5 6 7 8 9 1
@Entity public class Funcionario { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 2.32: Funcionario.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Departamento { @Id @GeneratedValue private Long id ; private String nome ; @OneToMany private Collection < Funcionario > funcionarios = new ArrayList < Funcionario >() ; // GETTERS E SETTERS }
Cdigo Java 2.33: Departamento.java
11
12
24
25
M APEAMENTO
Many to One
Suponha que em nosso domnio existam as entidades Pedido e Cliente. As duas classes que modelariam essas entidades seriam denidas com as anotaes principais de mapeamento.
1 2 3 4 5 6 @Entity class Pedido { @Id @GeneratedValue private Long id ; }
Cdigo Java 2.35: Pedido.java
1 2 3 4 5 6
Como existe um relacionamento entre pedidos e clientes, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Pedido. Supondo que um pedido pertena a um nico cliente, devemos utilizar um atributo simples para expressar esse relacionamento.
1 2 3 4 5 6 7 8 @Entity class Pedido { @Id @GeneratedValue private Long id ; private Cliente cliente ; }
Cdigo Java 2.37: Pedido.java
Para informar a cardinalidade do relacionamento entre pedidos e clientes, devemos utilizar a anotao @ManyToOne no atributo.
1 2 3 4 5 6 7 8 9 @Entity class Pedido { @Id @GeneratedValue private Long id ; @ManyToOne private Cliente cliente ; }
Cdigo Java 2.38: Pedido.java
No banco de dados, a tabela referente classe Pedido possuir uma join column vinculada tabela da classe Cliente. Por padro, o nome da join column formado pelo nome da entidade alvo
www.k19.com.br
25
M APEAMENTO
26
do relacionamento, seguido pelo caractere _ e pelo nome do atributo que dene a chave primria da entidade alvo.
No exemplo de pedidos e clientes, o nome da join column seria cliente_id. Podemos alterar o nome padro das join columns aplicando a anotao @JoinColumn.
1 2 3 4 5 6 7 8 9 1 @Entity class Pedido { @Id @GeneratedValue private Long id ; @ManyToOne @JoinColumn ( name = " cli_id " ) private Cliente cliente ; }
Cdigo Java 2.39: Pedido.java
Mais Sobre
Por padro, em um relacionamento Many to One, um objeto da primeira entidade no precisa estar necessariamente relacionado a um objeto da segunda entidade. Para exigir que cada objeto da primeira entidade esteja relacionado a um objeto da segunda entidade, devemos usar o atributo optional da anotao ManyToOne.
1 2 3 4 5 6 7 8 9 @Entity class Pedido { @Id @GeneratedValue private Long id ; @ManyToOne ( optional = false ) private Cliente cliente ; }
Cdigo Java 2.40: Pedido.java
Exerccios de Fixao
26
www.k19.com.br
27
M APEAMENTO
1 2 3 4 5 6 7 8 9 1
@Entity public class Cliente { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 2.41: Cliente.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14
@Entity public class Pedido { @Id @GeneratedValue private Long id ; @Temporal ( TemporalType . DATE ) private Calendar data ; @ManyToOne private Cliente cliente ; // GETTERS E SETTERS }
Cdigo Java 2.42: Pedido.java
14
Adicione um cliente e um departamento no banco de dados. Crie uma classe chamada Adiciona-
www.k19.com.br
27
M APEAMENTO
15
28
Abra o MySQL Workbench e observe as propriedades das tabelas Cliente e Pedido da base de dados K21_mapeamento_bd.
Many to Many
Suponha que em nosso domnio existam as entidades Livro e Autor. As classes com as anotaes bsicas de mapeamento seriam mais ou menos assim:
1 2 3 4 5 6 @Entity class Livro { @Id @GeneratedValue private Long id ; }
Cdigo Java 2.44: Livro.java
1 2 3 4 5 6
Como existe um relacionamento entre livros e autores, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Livro. Supondo que um livro possa ser escrito por muitos autores, devemos utilizar uma coleo para expressar esse relacionamento.
1 2 3 4 5 6 7 8 @Entity class Livro { @Id @GeneratedValue private Long id ; private Collection < Autor > autores ; }
Cdigo Java 2.46: Livro.java
Para informar a cardinalidade do relacionamento entre livros e autores, devemos utilizar a anotao @ManyToMany na coleo.
1 2 3 4 5 6 7 8 9 @Entity class Livro { @Id @GeneratedValue private Long id ; @ManyToMany private Collection < Autor > autores ; }
Cdigo Java 2.47: Livro.java
No banco de dados, alm das duas tabelas correspondentes s classes Livro e Autor, uma join table criada para relacionar os registros dos livros com os registros dos autores. Por padro, o nome
28
www.k19.com.br
29
M APEAMENTO
da join table a concatenao com _ dos nomes das duas entidades. No exemplo de livros e autores, o nome do join table seria Livro_Autor. Essa tabela possuir duas colunas vinculadas s entidades que formam o relacionamento. No exemplo, a join table Livro_Autor possuir uma coluna chamada Livro_id e outra chamada autores_id.
Para personalizar o nome join table e os nomes de suas colunas, podemos aplicar a anotao @JoinTable no atributo que dene o relacionamento.
1 2 3 4 5 6 7 8 9 1 11 12 @Entity class Livro { @Id @GeneratedValue private Long id ; @ManyToMany @JoinTable ( name = " Liv_Aut " , joinColumns = @JoinColumn ( name = " Liv_ID " ) , inverseJoinColumns = @JoinColumn ( name = " Aut_ID " ) ) private Collection < Autor > autores ; }
Cdigo Java 2.48: Livro.java
Exerccios de Fixao
16
29
M APEAMENTO
30
e Autor.
1 2 3 4 5 6 7 8 9 1 @Entity public class Autor { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 2.49: Autor.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Livro { @Id @GeneratedValue private Long id ; private String nome ; @ManyToMany private Collection < Autor > autores = new ArrayList < Autor >() ; // GETTERS E SETTERS }
Cdigo Java 2.50: Livro.java
17
Adicione um livro e um autor no banco de dados. Crie uma classe chamada AdicionaLivro-
Abra o MySQL Workbench e observe as propriedades das tabelas Livro, Autor e Livro_Autor da base de dados K21_mapeamento_bd.
18
30
www.k19.com.br
31
M APEAMENTO
Relacionamentos Bidirecionais
Quando expressamos um relacionamento colocando um atributo em uma das entidades, podemos acessar a outra entidade a partir da primeira. Por exemplo, considere o relacionamento entre governadores e estados.
1 2 3 4 5 6 7 8 9 1 11 @Entity class Estado { @Id @GeneratedValue private Long id ; @OneToOne private Governador governador ; // GETTERS E SETTERS }
Como o relacionamento est denido na classe Estado, podemos acessar o governador a partir de um estado.
1 2 Estado e = manager . find ( Estado . class , 1 L ) ; Governador g = e . getGovernador () ;
Tambm podemos expressar o relacionamento na classe Governador. Dessa forma, poderamos acessar um estado a partir de um governador.
1 2 3 4 5 6 7 8 9 1 11 @Entity class Governador { @Id @GeneratedValue private Long id ; @OneToOne private Estado estado ; // GETTERS E SETTERS }
1 2
A gura abaixo ilustra as tabelas Estado e Governador no banco de dados, assim como as join columns correspondentes aos relacionamentos.
www.k19.com.br
31
M APEAMENTO
32
Note que foram criadas duas colunas de relacionamentos. A primeira na tabela Estado com o nome governador_id e a segunda na tabela Governador com o nome estado_id. Nesse caso, o provedor JPA est considerando dois relacionamentos unidirecionais distintos entre essas entidades. No entanto, de acordo com o modelo relacional, a relao entre estados e governadores deveria ser expressa com apenas uma coluna de relacionamento. Ou seja, o relacionamento entre governadores e estados deveria ser bidirecional. Assim, devemos indicar em uma das classes que esse relacionamento bidirecional a juno de dois relacionamentos unidirecionais. Para isso, devemos adicionar o atributo mappedBy na anotao @OneToOne em uma das classes. O valor do mappedBy deve ser o nome do atributo que expressa o mesmo relacionamento na outra entidade.
1 2 3 4 5 6 7 8 9 1 11 @Entity class Governador { @Id @GeneratedValue private Long id ; @OneToOne ( mappedBy = " governador " ) private Estado estado ; // GETTERS E SETTERS }
Cdigo Java 2.56: Governador.java
Exerccios de Fixao
19 Considere um sistema de cobrana de ligaes telefnicas. Nesse sistema, temos uma entidade chamada Ligao e uma entidade chamada Fatura. Cada ligao est associada a uma nica fatura, enquanto que uma fatura est associada a mltiplas ligaes. Implemente classes para modelar essas duas entidades no pacote br.com.k19.modelo do projeto K19-Mapeamento.
1 2 3 4 5 6 7
@Entity public class Ligacao { @Id @GeneratedValue private Long id ; @ManyToOne private Fatura fatura ;
32
www.k19.com.br
33
8 9 1 11 12
M APEAMENTO
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Fatura { @Id @GeneratedValue private Long id ; @OneToMany private Collection < Ligacao > ligacoes = new ArrayList < Ligacao >() ; @Temporal ( TemporalType . DATE ) private Calendar vencimento ; // GETTERS E SETTERS }
Cdigo Java 2.58: Fatura.java
20
Faa um teste para adicionar algumas ligaes e uma fatura. Adicione no pacote br.com.k19.tes-
Atravs do MySQL Workbench, verique as tabelas criadas. Observe que a tabela Ligacao possui uma coluna de relacionamento chamada fatura_id e a tabela Fatura_Ligacao vincula os registros
21
www.k19.com.br
33
M APEAMENTO
34
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Fatura { @Id @GeneratedValue private Long id ; @OneToMany ( mappedBy = " fatura " ) private Collection < Ligacao > ligacoes = new ArrayList < Ligacao >() ; @Temporal ( TemporalType . DATE ) private Calendar vencimento ; // GETTERS E SETTERS }
Cdigo Java 2.60: Fatura.java
Execute a classe AdicionaFaturaLigacao para adicionar uma fatura e algumas ligaes. Atravs do MySQL Workbench, verique as tabelas criadas. Note que foram criadas apenas duas tabelas: Fatura e Ligacao.
24
Objetos Embutidos
Suponha que em nosso domnio exista uma entidade chamada Pessoa. Toda pessoa possui um endereo, que formado por pas, estado, cidade, logradouro, nmero, complemento e CEP. Para melhorar a organizao da nossa aplicao, podemos criar duas classes: Pessoa e Endereco.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 @Entity class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; @Temporal ( TemporalType . DATE ) private Calendar nascimento ; @OneToOne private Endereco endereco ; }
Cdigo Java 2.61: Pessoa.java
1 2 3 4 5 6 7 8 9
@Entity class Endereco { @Id @GeneratedValue private Long id ; private String pais ; private String estado ;
34
www.k19.com.br
35
1 11 12 13 14 15 16 17 18 19 2
M APEAMENTO
private String cidade ; private String logradouro ; private int numero ; private String complemento ; private int cep ; }
Cdigo Java 2.62: Endereco.java
Da forma como os mapeamentos esto denidos, duas tabelas sero criadas: uma para a classe Pessoa e outra para a classe Endereco. Na tabela Pessoa, haver uma coluna de relacionamento. Para recuperar os dados do endereo de uma pessoa, duas tabelas precisam ser consultadas atravs de uma operao de join. Esse tipo de operao no banco de dados custoso. Suponha que a tabela Endereco esteja relacionada apenas com a tabela Pessoa. Nesse caso, seria interessante se pudssemos guardar os endereos das pessoas na prpria tabela Pessoa, tornando desnecessria a existncia da tabela Endereco. No entanto, gostaramos de manter as classes Pessoa e Endereco. Isso pode ser feito da seguinte forma. Na classe Pessoa, devemos remover a anotao de cardinalidade @OneToOne. Na classe Endereco, devemos substituir a anotao @Entity por @Embeddable. Alm disso, no devemos denir uma chave para a classe Endereco, pois ela no dene uma entidade.
1 2 3 4 5 6 7 8 9 1 11 12 13 @Entity class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; @Temporal ( TemporalType . DATE ) private Calendar nascimento ; private Endereco endereco ; }
Cdigo Java 2.63: Pessoa.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16
@Embeddable class Endereco { private String pais ; private String estado ; private String cidade ; private String logradouro ; private int numero ; private String complemento ; private int cep ; }
www.k19.com.br
35
M APEAMENTO
36
Podemos conseguir o mesmo resultado da seguinte forma. Na classe Pessoa, devemos substituir a anotao de cardinalidade @OneToOne por @Embedded. Na classe Endereco, devemos remover a anotao @Entity. Tambm, no devemos denir uma chave para a classe Endereco, pois ela no dene uma entidade.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 @Entity class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; @Temporal ( TemporalType . DATE ) private Calendar nascimento ; @Embedded private Endereco endereco ; }
Cdigo Java 2.65: Pessoa.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
class Endereco { private String pais ; private String estado ; private String cidade ; private String logradouro ; private int numero ; private String complemento ; private int cep ; }
Cdigo Java 2.66: Endereco.java
Exerccios de Fixao
25 Crie uma classe para modelar endereos no pacote br.com.k19.modelo do projeto K19-Mapeamento.
1 2 3 4 5 6 7 8 9 1 11 12
public class Endereco { private String estado ; private String cidade ; private String logradouro ; private int numero ; // GETTERS E SETTERS }
36
www.k19.com.br
37
M APEAMENTO
26
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16
Crie uma classe chamada AdicionaCandidatoEndereco no pacote br.com.k19.testes do projeto K19-Mapeamento para adicionar alguns candidatos e endereos e depois execute-a.
27
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27
public class AdicionaCandidatoEndereco { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Endereco e = new Endereco () ; e . setEstado ( " So Paulo " ) ; e . setCidade ( " So Paulo " ) ; e . setLogradouro ( " Av . Bigadeiro Faria Lima " ) ; e . setNumero (1571) ; Candidato p = new Candidato () ; p . setNome ( " Rafael Cosentino " ) ; p . setNascimento ( new GregorianCalendar (1984 , 1 , 3 ) ) ; p . setEndereco ( e ) ; manager . persist ( p ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 2.69: AdicionaPessoaEndereco.java
Execute a classe AdicionaCandidatoEndereco para adicionar um candidato e seu endereo. Atravs do MySQL Workbench, verique a tabelas criada. Note que foi criada apenas a tabela Candidato.
28
Herana
www.k19.com.br
37
M APEAMENTO
38
O mapeamento objeto-relacional descreve como os conceitos de orientao a objetos so mapeados para os conceitos do modelo relacional. De todos os conceitos de orientao a objetos, um dos mais complexos de se mapear o de Herana. A especicao JPA dene trs estratgias para realizar o mapeamento de herana.
Single Table
A estratgia Single Table a mais comum e a que possibilita melhor desempenho em relao a velocidade das consultas. Nessa estratgia, a super classe deve ser anotada com
@Inheritance(strategy=InheritanceType.SINGLE_TABLE).
O provedor JPA criar apenas uma tabela com o nome da super classe para armazenar os dados dos objetos criados a partir da super classe ou das sub classes. Todos os atributos da super classe e os das sub classes sero mapeados para colunas dessa tabela. Alm disso, uma coluna especial chamada DTYPE ser utilizada para identicar a classe do objeto correspondente ao registro.
1 2 3 4 5 6 7 8 @Entity @Inheritance ( strategy = InheritanceType . SINGLE_TABLE ) public class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; }
Cdigo Java 2.70: Pessoa.java
1 2 3 4
1 2 3 4
38
www.k19.com.br
39
M APEAMENTO
A desvantagem da Single Table o consumo desnecessrio de espao, j que nem todos os campos so utilizados para todos os registros. Por exemplo, se uma pessoa jurdica fosse cadastrada, o campo cpf no seria utilizado. Da mesma forma, se uma pessoa fsica fosse cadastrada, o campo cnpj no seria utilizado.
Joined
Nessa estratgia, uma tabela para cada classe da hierarquia criada. Em cada tabela, apenas os campos referentes aos atributos da classe correspondente so adicionados. Para relacionar os registros das diversas tabelas e remontar os objetos quando uma consulta for realizada, as tabelas relacionadas s sub-classes possuem chaves estrangeiras vinculadas tabela associada super-classe.
1 2 3 4 5 6 7 8 @Entity @Inheritance ( strategy = InheritanceType . JOINED ) public class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; }
Cdigo Java 2.73: Pessoa.java
1 2 3 4
1 2 3 4
www.k19.com.br
39
M APEAMENTO
40
O consumo de espao utilizando a estratgia Joined menor do que o utilizado pela estratgia Single Table. Contudo, as consultas so mais lentas, pois necessrio realizar operaes de join para recuperar os dados dos objetos.
1 2 3 4
1 2 3 4
40
www.k19.com.br
41
M APEAMENTO
Na estratgia Table Per Class, no podemos utilizar a gerao automtica de chave primrias simples e numricas.
Exerccios de Fixao
Adicione uma classe chamada Pessoa no pacote br.com.k19.modelo do projeto K19-Mapeamento.
29
1 2 3 4 5 6 7 8 9 1
@Entity @Inheritance ( strategy = InheritanceType . SINGLE_TABLE ) public class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 2.79: Pessoa.java
30
1 2 3 4 5 6
31
1 2 3 4 5 6
32
Faa um teste para adicionar pessoas. Crie uma classe chamada AdicionaPessoa no pacote
www.k19.com.br
41
M APEAMENTO
3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28 29 EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Pessoa p1 = new Pessoa () ; p1 . setNome ( " Marcelo " ) ; PessoaFisica p2 = new PessoaFisica () ; p2 . setNome ( " Rafael " ) ; p2 . setCpf ( " 1234 " ) ; PessoaJuridica p3 = new PessoaJuridica () ; p3 . setNome ( " K19 " ) ; p3 . setCnpj ( " 567788 " ) ; manager . persist ( p1 ) ; manager . persist ( p2 ) ; manager . persist ( p3 ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 2.82: AdicionaPessoa.java
42
Execute a classe AdicionaPessoa para adicionar algumas pessoas. Atravs do MySQL Workbench, verique a tabela criada. Note que foi criada apenas a tabela Pessoa.
33
42
www.k19.com.br
CAPTULO
E NTITY M ANAGER
Segundo a especicao JPA, as instncias das entidades so administradas pelos Entity Managers. As duas principais responsabilidades dos Entity Managers so gerenciar o estado dos objetos e sincronizar os dados da aplicao e do banco de dados.
Estados
necessrio conhecer o ciclo de vida das entidades para saber como os objetos so administrados pelos Entity Managers. Uma instncia de uma entidade pode passar pelos seguintes estados: Novo (New): Um objeto nesse estado no possui uma identidade (chave) e no est associado a um Entity Manager. O contedo desse objeto no enviado para o banco de dados. Toda instncia de uma entidade que acabou de ser criada com o comando new encontra-se no estado new do JPA. Administrado (Managed): Um objeto no estado managed possui uma identidade e est associado a um Entity Manager. A cada sincronizao, os dados de um objeto no estado managed so atualizados no banco de dados. Desvinculado (Detached): Um objeto no estado detached possui uma identidade, mas no est associado a um Entity Manager. Dessa forma, o contedo desse objeto no sincronizado com o banco de dados. Removido (Removed): Um objeto no estado removed possui uma identidade e est associado a um Entity Manager. O contedo desse objeto ser removido do banco de dados quando houver uma sincronizao.
43
E NTITY M ANAGER
44
Para conrmar uma transao, devemos usar o mtodo commit(). Quando esse mtodo invocado, ocorre uma sincronizao com o banco de dados e a transao nalizada.
1 2 3 manager . getTransaction () . begin () ; ... manager . getTransaction () . commit () ;
Cdigo Java 3.1: Iniciando e conrmando uma transao
Com uma transao ativa, tambm podemos disparar uma sincronizao atravs do mtodo
flush(). Apesar dos dados serem enviados para o banco de dados, eles no caro visveis para
outras transaes. Esses dados sero considerados apenas nas consultas efetuadas dentro da prpria transao. Diversas chamadas ao mtodo flush() podem ser efetuadas dentro de uma mesma transao.
1 2 3 4 5 manager . getTransaction () . begin () ; ... manager . flush () ; ... manager . getTransaction () . commit () ;
Cdigo Java 3.2: Sincronizaes parciais atravs do mtodo flush()
Toda modicao, remoo ou insero realizada no banco de dados devido s chamadas ao mtodo flush() podem ser desfeitas atravs do mtodo rollback(). Uma chamada a esse mtodo tambm naliza a transao.
1 2 3 4 5 manager . getTransaction () . begin () ; ... manager . flush () ; ... manager . getTransaction () . rollback () ;
Cdigo Java 3.3: Sincronizaes parciais atravs do mtodo flush()
Flush Mode
H duas polticas adotadas pelos provedores JPA em relao s sincronizaes: FlushModeType.AUTO (padro) e FlushModeType.COMMIT. No modo AUTO, o provedor JPA realiza sincronizaes automticas antes de uma operao de consulta para garantir que as modicaes, remoes e inseres ainda no sincronizadas sejam consideradas na consulta. J o comportamento no modo COMMIT no est especicado. Consequentemente, cada provedor pode implementar o comportamento que achar mais adequado. Podemos congurar o ush mode no nvel de um Entity Manager afetando o comportamento em todas as consultas realizadas atravs desse Entity Manager ou congurar apenas para uma consulta.
1 manager . setFlushMode ( FlushModeType . COMMIT ) ;
Cdigo Java 3.4: Congurando o ush mode de um Entity Manager
1 2
44
www.k19.com.br
45
E NTITY M ANAGER
Transies
Uma instncia de uma entidade pode mudar de estado. Veremos a seguir as principais transies.
New Managed
Um objeto no estado new passa para o estado managed quando utilizamos o mtodo persist() dos Entity Managers.
1 2 3 4 5 6 7 8 9 1 @Entity class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 3.6: Pessoa.java
1 2 3 4 5 6 7
manager . getTransaction () . begin () ; Pessoa p = new Pessoa () ; p . setNome ( " Rafael Cosentino " ) ; manager . persist () ; manager . getTransaction () . commit () ;
Cdigo Java 3.7: Persistindo uma instncia de uma entidade
BD Managed
Quando dados so recuperados do banco de dados, o provedor JPA cria objetos para armazenar essas informaes. Esses objetos estaro no estado managed.
1 Pessoa p = manager . find ( Pessoa . class , 1 L ) ;
1 2
Query query = manager . createQuery ( " select p from Pessoa p " ) ; List < Pessoa > lista = query . getResultList () ;
Managed Detached
Quando no queremos mais que um objeto no estado managed seja administrado, podemos desvincul-lo do seu Entity Manager tornando-o detached. Dessa forma, o contedo desse objeto no ser mais sincronizado com o banco de dados.
www.k19.com.br
45
E NTITY M ANAGER
46
Para tornar detached todos os objetos administrados por um Entity Manager, devemos utilizar o mtodo clear().
1 manager . clear () ;
Na chamada do mtodo close(), todos os objetos administrados por um Entity Manager tambm passam para o estado detached.
1 manager . close () ;
Detached Managed
O estado de um objeto detached pode ser propagado para um objeto managed com a mesma identidade para que os dados sejam sincronizados com o banco de dados. Esse processo realizado pelo mtodo merge().
1 Pessoa pessoaManaged = manager . merge ( pessoaDetached ) ;
Managed Removed
Quando um objeto managed se torna detached, os dados correspondentes a esse objeto no so apagados do banco de dados. Agora, quando utilizamos o mtodo remove(), marcamos um objeto para ser removido do banco de dados.
1 2 Pessoa p = manager . find ( Pessoa . class , 1 L ) ; manager . remove ( p ) ;
O contedo do objeto ser removido no banco de dados quando o provedor realizar uma sincronizao.
Managed Managed
O contedo de um objeto no estado managed pode car desatualizado em relao ao banco de dados se algum ou alguma aplicao alterar os dados na base de dados. Para atualizar um objeto managed com os dados do banco de dados, devemos utilizar o mtodo refresh().
1 2 Pessoa p = manager . find ( Pessoa . class , 1 L ) ; manager . refresh ( p ) ;
Exerccios de Fixao
46
www.k19.com.br
47
E NTITY M ANAGER
Crie um projeto no eclipse chamado K19-EntityManager. Copie a pasta lib do projeto K19JPA2-Hibernate para o projeto K19-EnityManager. Depois adicione os jars dessa pasta no classpath desse novo projeto.
1 2 Abra o MySQL Workbench e apague a base de dados K21_entity_manager_bd se ela existir. Depois crie a base de dados K21_entity_manager_bd.
Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-EntityManager. Altere o arquivo persistence.xml do projeto K19-EntityManager, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
3
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22
< persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_entity_manager_pu " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_entity_manager_bd " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML 3.1: persistence.xml
1 2 3 4 5 6 7 8 9 1
@Entity public class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 3.17: Pessoa.java
Persista objetos atravs de um Entity Manager. Crie uma classe chamada TestePersist dentro de um pacote chamado br.com.k19.testes no projeto K19-EntityManager.
5
1 2 3 4 5
public class TestePersist { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ;
www.k19.com.br
47
E NTITY M ANAGER
6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25
48
// ABRINDO A TRASACAO manager . getTransaction () . begin () ; // OBJETO NO ESTADO NEW Pessoa p = new Pessoa () ; p . setNome ( " Rafael Cosentino " ) ; // OBJETO NO ESTADO MANAGED manager . persist ( p ) ; // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager . getTransaction () . commit () ; System . out . println ( " Pessoa id : " + p . getId () ) ; manager . close () ; factory . close () ; } }
Cdigo Java 3.18: TestePersist.java
Execute e consulte o banco de dados atravs do MySQL Workbench! Busque objetos atravs de um Entity Manager dado a identidade dos objetos. Crie uma classe chamada TesteFind dentro de um pacote br.com.k19.testes no projeto K19-EntityManager.
6
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
public class TesteFind { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; // OBJETO NO ESTADO MANAGED Pessoa p = manager . find ( Pessoa . class , 1 L ) ; System . out . println ( " Id : " + p . getId () ) ; System . out . println ( " Nome : " + p . getNome () ) ; manager . close () ; factory . close () ; } }
Cdigo Java 3.19: TesteFind.java
Execute e observe as mensagens no Console! Altere objetos no estado managed e depois faa um sincronizao com o banco de dados atravs de uma chamada ao mtodo commit(). Crie uma classe chamada TesteManaged dentro de um pacote br.com.k19.testes no projeto K19-EntityManager.
7
1 2 3 4 5 6 7 8 9 1 11 12 13
public class TesteManaged { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; // OBJETO NO ESTADO MANAGED Pessoa p = manager . find ( Pessoa . class , 1 L ) ; // ALTERANDO O CONTEUDO DO OBJETO p . setNome ( " Marcelo Martins " ) ;
48
www.k19.com.br
49
14 15 16 17 18 19 2 21
E NTITY M ANAGER
// SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 3.20: TesteManaged.java
Execute e consulte o banco de dados atravs do MySQL Workbench! Altere objetos no estado detached e depois faa um sincronizao com o banco de dados atravs de uma chamada ao mtodo commit(). Crie uma classe chamada TesteDetached dentro de um pacote br.com.k19.testes no projeto K19-EntityManager.
8
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24
public class TesteDetached { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; // OBJETO NO ESTADO MANAGED Pessoa p = manager . find ( Pessoa . class , 1 L ) ; // OBJETO NO ESTADO DETACHED manager . detach ( p ) ; // ALTERANDO O CONTEUDO DO OBJETO p . setNome ( " Jonas Hirata " ) ; // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 3.21: TesteDetached.java
Execute e consulte o banco de dados atravs do MySQL Workbench! Busque um objeto no banco e ento desvincule-o atravs do mtodo detach(). Passe esse objeto como parmetro para o mtodo merge() e ento altere uma propriedade do objeto devolvido. Faa um sincronizao com o banco de dados atravs de uma chamada ao mtodo commit(). Crie uma classe chamada TesteMerge dentro de um pacote br.com.k19.testes no projeto K19EntityManager.
9
1 2 3 4 5 6 7 8 9 1 11 12
public class TesteMerge { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; // OBJETO NO ESTADO MANAGED Pessoa p = manager . find ( Pessoa . class , 1 L ) ; // OBJETO NO ESTADO DETACHED
www.k19.com.br
49
E NTITY M ANAGER
13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 manager . detach ( p ) ; // OBJETO p2 NO ESTADO MANAGED Pessoa p2 = manager . merge ( p ) ; // ALTERANDO O CONTEUDO DO OBJETO p2 . setNome ( " Jonas Hirata " ) ; // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
50
Execute e consulte o banco de dados atravs do MySQL Workbench! Busque por objetos no banco de dados e depois remova-os. Faa uma sincronizao com o banco de dados atravs de uma chamada ao mtodo commit(). Crie uma classe chamada TesteRemoved dentro de um pacote br.com.k19.testes no projeto K19-EntityManager.
10
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21
public class TesteRemoved { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; // OBJETO NO ESTADO MANAGED Pessoa p = manager . find ( Pessoa . class , 1 L ) ; // OBJETO NO ESTADO REMOVED manager . remove ( p ) ; // SINCRONIZANDO E CONFIRMANDO A TRANSACAO manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
LAZY e EAGER
Como os Entity Managers administram as instncias das entidades, eles so responsveis pelo carregamento do estado dos objetos. H dois modos de carregar um objeto com os dados obtidos de um banco de dados: LAZY e EAGER. No modo LAZY, o provedor posterga ao mximo a busca dos dados no banco de dados. J no modo EAGER, o provedor busca imediatamente os dados no banco de dados.
50
www.k19.com.br
51
E NTITY M ANAGER
nd() VS getReference()
Tanto o mtodo find() quanto o mtodo getReference() permitem que a aplicao obtenha instncias das entidades a partir das identidades dos objetos. A diferena entre eles que o find() tem comportamento EAGER e o getReference() tem comportamento LAZY. No exemplo abaixo, um objeto buscado no banco de dados atravs do mtodo find(). Dessa forma, os dados do objeto so carregados imediatamente.
1 2 Pessoa p = manager . find ( Pessoa . class , 1 L ) ; // o objeto j est carregado
Cdigo Java 3.24: Buscando um objeto com o mtodo find()
No exemplo abaixo, usamos o mtodo getReference() para buscar os dados de um objeto no banco de dados. Como o comportamento desse mtodo LAZY, os dados do objeto so carregados apenas quando o estado desse objeto acessado pela primeira vez. Por exemplo, na chamada ao mtodo getNome().
1 2 3 4 Pessoa p = manager . getReference ( Pessoa . class , 1 L ) ; // o objeto no est carregado ainda String nome = p . getNome () ; // agora o objeto est carregado
Cdigo Java 3.25: Buscando um objeto com o mtodo getReference()
Quando recuperamos o valor da propriedade nome atravs do mtodo getNome(), os demais atributos de tipos bsicos tambm so carregados.
www.k19.com.br
51
E NTITY M ANAGER
52
Importante
O modo LAZY para atributos bsicos s pode ser aceito pelos provedores se o modo de acesso for Property Access.
1 2 3 4 5 6
Por padro, quando os dados de um estado so recuperados do banco de dados, os dados do governador associado a esse estado tambm so recuperados. Em outras palavras, o modo de carregamento padro do atributo que estabelece o relacionamento entre estados e governadores EAGER. Podemos alterar esse comportamento padro aplicando a propriedade fetch na anotao @OneToOne.
1 2 3 4 5 6 7 8 9 @Entity class Estado { @Id @GeneratedValue private Long id ; @OneToOne ( fetch = FetchType . LAZY ) private Governador governador ; }
Cdigo Java 3.29: Estado.java
O modo de carregamento dos relacionamentos do tipo One To One e Many To One EAGER por padro. O modo de carregamento dos relacionamentos do tipo One To Many e Many To Many , por padro, LAZY. Lembrando que o modo de carregamento pode ser denido com a propriedade fetch das anotaes de relacionamento.
1 2 @OneToOne ( fetch = FetchType . LAZY ) @ManyToOne ( fetch = FetchType . LAZY )
52
www.k19.com.br
53
3 4 @OneToMany ( fetch = FetchType . EAGER ) @ManyToMany ( fetch = FetchType . EAGER )
Cdigo Java 3.30: Denindo o modo de carregamento para relacionamentos
E NTITY M ANAGER
Importante
No modo de carregamento LAZY, o provedor JPA posterga ao mximo o carregamento de um objeto. Esse carregamento s poder ser feito posteriormente se o Entity Manager que administra esse objeto estiver aberto. Caso a aplicao tente acessar o contedo no carregado de um objeto aps o fechamento do Entity Manager que o administra, o provedor lanar uma exceo.
Exerccios de Fixao
11 Teste o comportamento do mtodo de busca find(). Crie um classe chamada TesteFindEager no pacote br.com.k19.testes no projeto K19-EntityManager. Observe que o cdigo abaixo supe a existncia de registro com identicador igual a 1 na tabela correspondente classe Pessoa. Caso esse registro no exista, busque por um que exista, escolhendo um identicador adequado na chamada do mtodo find().
1 2 3 4 5 6 7 8 9 1 11 12 13 14
public class TesteFindEager { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; System . out . println ( " ----------- CHAMANDO O FIND - - - - - - - - - - - - " ) ; Pessoa p = manager . find ( Pessoa . class , 1 L ) ; System . out . println ( " ----------- FEZ O SELECT - - - - - - - - - - - - - - - " ) ; manager . close () ; factory . close () ; } }
Cdigo Java 3.31: TesteFindEager.java
Execute e veja a sada! Teste o comportamento do mtodo de busca getReference(). Crie um classe chamada TesteGetReferenceLazy no pacote br.com.k19.testes do projeto K19-EntityManager.
12
1 2 3 4 5 6 7 8 9 1 11 12 13
public class TesteGetReferenceLazy { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; System . out . println ( " ----------- CHAMANDO O GETREFERENCE - - - - " ) ; Pessoa p = manager . getReference ( Pessoa . class , 1 L ) ; System . out . println ( " ----------- NAO FEZ O SELECT - - - - - - - - - - - " ) ; manager . close () ; factory . close () ; }
www.k19.com.br
53
E NTITY M ANAGER
14 }
Cdigo Java 3.32: TesteGetReferenceLazy.java
54
Execute e veja a sada! Teste o problema de Lazy Initialization. Crie um classe chamada TesteLazyInitialization no pacote br.com.k19.testes do projeto K19-EntityManager.
13
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16
public class TesteLazyInitialization { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; // OBJETO CARREGADO EM MODO LAZY Pessoa p = manager . getReference ( Pessoa . class , 1 L ) ; manager . close () ; factory . close () ; // TENTA USAR UM DADO DO OBJETO System . out . println ( p . getNome () ) ; } }
Cdigo Java 3.33: TesteLazyInitialization.java
Execute e veja a sada! Crie duas classes para modelar governadores e estados, estabelecendo um relacionamento One to One entre essas entidades. Essas classes devem ser adicionadas no pacote br.com.k19.modelo do projeto K19-EntityManager.
14
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Estado { @Id @GeneratedValue private Long id ; private String nome ; @OneToOne private Governador governador ; // GETTERS E SETTERS }
Cdigo Java 3.34: Estado.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Governador { @Id @GeneratedValue private Long id ; private String nome ; @OneToOne ( mappedBy = " governador " ) private Estado estado ; // GETTERS E SETTERS }
54
www.k19.com.br
55
E NTITY M ANAGER
Adicione um governador e um estado. Crie uma classe chamada AdicionaGovernadorEstado no pacote br.com.k19.testes do projeto K19-EntityManager.
15
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26
public class AdicionaGovernadorEstado { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Governador governador = new Governador () ; governador . setNome ( " Rafael Cosentino " ) ; Estado estado = new Estado () ; estado . setNome ( " So Paulo " ) ; governador . setEstado ( estado ) ; estado . setGovernador ( governador ) ; manager . persist ( estado ) ; manager . persist ( governador ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 3.36: AdicionaGovernadorEstado.java
Teste o carregamento EAGER no relacionamento One to One entre estados e governadores. Crie uma classe chamada TesteCarregamentoRelacionamento no pacote br.com.k19.testes do projeto K19-EntityManager.
16
1 2 3 4 5 6 7 8
public class TesteCarregamentoRelacionamento { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; Estado estado = manager . find ( Estado . class , 1 L ) ; } }
Cdigo Java 3.37: TesteCarregamentoRelacionamento.java
Observe a sada no console para vericar o carregamento tanto do estado quanto do governador.
17 Altere a poltica padro do carregamento do governador adicionando a propriedade fetch na anotao @OneToOne na classe Estado.
1 2
www.k19.com.br
55
E NTITY M ANAGER
18
56
Execute novamente a classe TesteCarregamentoRelaciomento e observe a sada do console para vericar que agora somente o estado carregado.
19
1 2 3 4 5 6 7 8 9 1 11 12 13
Caching
Considere uma aplicao de cadastramento de pessoas. No formulrio de cadastro de uma pessoa, o usurio deve selecionar o estado e a cidade onde a pessoa nasceu. A lista de cidades ca armazenada em uma tabela do banco de dados. As cidades so modeladas pela seguinte classe:
1 2 3 4 5 6 7 8 9 1 @Entity public class Cidade { @Id @GeneratedValue private Long id ; private String nomeDaCidade ; private String nomeDoEstado ; }
Cdigo Java 3.40: Cidade.java
O contedo da tabela de cidades raramente alterado por motivos bvios. Constantemente, a aplicao realizar consultas a essa tabela. Tendo em mente que o custo para trazer dados do banco de dados para a memria da aplicao alto, poderamos melhorar o desempenho da aplicao se mantivssemos a lista das cidades em memria. Em situaes como essa, podemos aplicar o conceito de caching. O caching consiste em manter uma cpia dos dados para evitar o constante acesso ao dispositivo de armazenamento de dados. Os provedores JPA disponibilizam alguns tipos de cache. Veremos o funcionamento de cada um deles a seguir.
57
E NTITY M ANAGER
Um objeto j carregado por um Entity Manager mantido no persistence context (cache de primeiro nvel). Cada Entity Manager possui o seu prprio persistence context. Se a aplicao buscar um objeto atravs de um Entity Manager e ele j estiver carregado no Persistence Context correspondente, a busca no ser realizado no banco de dados, evitando assim uma operao no banco de dados.
Exerccios de Fixao
Verique o comportamento dos Entity Managers ao buscar duas vezes o mesmo objeto. Crie uma classe chamada TestePersistenceContext no pacote br.com.k19.testes do projeto K19EntityManager.
20
1 2 3 4 5 6 7 8 9 1 11 12
public class TestePersistenceContext { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; System . out . println ( " ------------------ PRIMEIRO FIND - - - - - - - - - - - - - - - - - " ) ; Estado estado = manager . find ( Estado . class , 1 L ) ; System . out . println ( " ------------------ SEGUNDO FIND - - - - - - - - - - - - - - - - - - " ) ; estado = manager . find ( Estado . class , 1 L ) ; } }
Cdigo Java 3.41: TestePersistenceContext.java
Execute e observe a sada no console para vericar que o provedor s realiza uma busca
57
E NTITY M ANAGER
58
Exerccios de Fixao
Entre na pasta K19-Arquivos/hibernate-release-4.1.2.Final/lib da rea de Trabalho e copie os jars da pasta optional/ehcache e da pasta jpa para a pasta lib do projeto K19-EntityManager. Depois adicione esses jars no build path do projeto.
21 22
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28
No pacote br.com.k19.modelo do projeto K19-EntityManager, crie uma entidade para representar cidades. Habilite o cache de segundo nvel para essa entidade.
23
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity @Cacheable ( true ) public class Cidade { @Id @GeneratedValue private Long id ; private String nomeDaCidade ; private String nomeDoEstado ; // GETTERS E SETTERS }
Cdigo Java 3.42: Cidade.java
No pacote br.com.k19.testes do projeto K19-EntityManager, crie uma classe chamada InsereCidades para inserir algumas cidades no banco de dados.
24
58
www.k19.com.br
59
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28 29 3 31 public class InsereCidades { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Cidade saoPaulo = new Cidade () ; saoPaulo . setNomeDaCidade ( " So Paulo " ) ; saoPaulo . setNomeDoEstado ( " So Paulo " ) ; Cidade rioDeJaneiro = new Cidade () ; rioDeJaneiro . setNomeDaCidade ( " Rio de Janeiro " ) ; rioDeJaneiro . setNomeDoEstado ( " Rio de Janeiro " ) ; Cidade natal = new Cidade () ; natal . setNomeDaCidade ( " Natal " ) ; natal . setNomeDoEstado ( " Rio Grande do Norte " ) ; manager . persist ( saoPaulo ) ; manager . persist ( rioDeJaneiro ) ; manager . persist ( natal ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 3.43: InsereCidades.java
E NTITY M ANAGER
No pacote br.com.k19.testes do projeto K19-EntityManager, crie uma classe para testar o funcionamento do cache de segundo nvel.
25
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
public class TesteSharedCache { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager1 = factory . createEntityManager () ; System . out . println ( " ------------------ PRIMEIRO FIND - - - - - - - - - - - - - - - - - " ) ; Cidade cidade = manager1 . find ( Cidade . class , 1 L ) ; EntityManager manager2 = factory . createEntityManager () ; System . out . println ( " ------------------ SEGUNDO FIND - - - - - - - - - - - - - - - - - - " ) ; cidade = manager2 . find ( Cidade . class , 1 L ) ; } }
Cdigo Java 3.44: TesteSharedCache.java
Cascade
Por padro, as operaes dos Entity Managers so aplicadas somente ao objeto passado como parmetro para o mtodo que implementa a operao, ou seja, essas operaes no so aplicadas aos objetos relacionados ao objeto passado como parmetro. Por exemplo, suponha um relacionamento
www.k19.com.br
59
E NTITY M ANAGER
60
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Governador { @Id @GeneratedValue private Long id ; private String nome ; @OneToOne ( mappedBy = " governador " ) private Estado estado ; // GETTERS E SETTERS }
Cdigo Java 3.46: Governador.java
Suponha que um objeto da classe Estado e outro da classe Governador sejam criados e associados. Se apenas um dos objetos for persistido um erro ocorrer na sincronizao com o banco de dados.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 manager . getTransaction () . begin () ; Governador governador = new Governador () ; governador . setNome ( " Rafael Cosentino " ) ; Estado estado = new Estado () ; estado . setNome ( " So Paulo " ) ; governador . setEstado ( estado ) ; estado . setGovernador ( governador ) ; manager . persist ( estado ) ; manager . getTransaction () . commit () ;
Cdigo Java 3.47: Persistindo apenas um objeto
60
www.k19.com.br
61
E NTITY M ANAGER
Ou ento podemos congurar a operao persist() para que ela seja aplicada em cascata. Essa congurao pode ser realizada atravs do atributo cascade das anotaes de relacionamento.
1 2 @OneToOne ( cascade = CascadeType . PERSIST ) private Governador governador ;
Cdigo Java 3.49: Congurando a operao persist() em cascata
O atributo cascade das anotaes de relacionamento pode ser utilizado para congurar o comportamento em cascata para as outras operaes dos Entity Managers. CascadeType.PERSIST CascadeType.DETACH CascadeType.MERGE CascadeType.REFRESH CascadeType.REMOVE CascadeType.ALL
Importante
O atributo cascade unidirecional. Dessa forma, nos relacionamentos bidirecionais para ter o comportamento do cascade nas duas direes necessrio utilizar a propriedade cacasde nas duas entidades.
Exerccios de Fixao
26 Tente persistir um governador e um estado. Crie uma classe chamada TesteCascade no pacote br.com.k19.testes do projeto K19-EntityManager.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class TesteCascade { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; Governador governador = new Governador () ; governador . setNome ( " Rafael Cosentino " ) ; Estado estado = new Estado () ; estado . setNome ( " So Paulo " ) ; governador . setEstado ( estado ) ; estado . setGovernador ( governador ) ; manager . getTransaction () . begin () ; manager . persist ( estado ) ; manager . getTransaction () . commit () ; } }
Cdigo Java 3.50: TesteCascade.java
www.k19.com.br
61
E NTITY M ANAGER
62
Execute e observe o erro Modique a classe Estado para congurar a propriedade cascade no relacionamento com governadores.
27
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Estado { @Id @GeneratedValue private Long id ; private String nome ; @OneToOne ( cascade = CascadeType . PERSIST , fetch = FetchType . LAZY ) private Governador governador ; // GETTERS E SETTERS }
Cdigo Java 3.51: Estado.java
28 Execute a classe TesteCascade e observe que no ocorre o mesmo erro que aconteceu anteriormente.
1 2 3 4 5 6 7 8 9 1 11
@Entity public class Comentario { @Id @GeneratedValue private Long id ; @Temporal ( TemporalType . DATE ) private Calendar data ; // GETTERS E SETTERS }
62
www.k19.com.br
63
E NTITY M ANAGER
1 2 3 4 5 6 7 8
Topico topico = manager . find ( Topico . class , 1 L ) ; manager . getTransaction () . begin () ; // os comentrios desse tpico sero removidos em cascata manager . remove ( topico ) ; manager . getTransaction () . commit () ;
Cdigo Java 3.54: Removendo um tpico e seus comentrios
Contudo, se os vnculos entre um tpico e seus comentrios forem desfeitos, os comentrios no sero removidos automaticamente. No exemplo abaixo, os comentrios sero mantidos no banco de dados.
1 2 3 4 5 6 7 Topico topico = manager . find ( Topico . class , 1 L ) ; manager . getTransaction () . begin () ; topico . getComentarios () . clear () ; manager . getTransaction () . commit () ;
Cdigo Java 3.55: Desvinculando os comentrios de um tpico
Podemos determinar que todo comentrio no vinculado a um tpico deve ser automaticamente removido. Essa congurao pode ser realizada atravs do atributo orphanRemoval das anotaes @OneToOne e @OneToMany. Veja o exemplo a seguir.
1 2 3 4 5 6 7 8 9 1 11 12 13 @Entity public class Topico { @Id @GeneratedValue private Long id ; @OneToMany ( orphanRemoval = true ) private List < Comentario > comentarios ; private String titulo ; // GETTERS E SETTERS }
Cdigo Java 3.56: Topico.java
Exerccios de Fixao
29
63
E NTITY M ANAGER
1 2 3 4 5 6 7 8 9 1 11 @Entity public class Comentario { @Id @GeneratedValue private Long id ; @Temporal ( TemporalType . DATE ) private Calendar data ; // GETTERS E SETTERS }
64
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Topico { @Id @GeneratedValue private Long id ; @OneToMany ( cascade ={ CascadeType . PERSIST , CascadeType . REMOVE }) private List < Comentario > comentarios = new ArrayList < Comentario >() ; private String titulo ; // GETTERS E SETTERS }
Adicione um tpico e alguns comentrios. Crie uma classe chamada AdicionaTopicoComentarios no pacote br.com.k19.testes do projeto K19-EntityManager.
30
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25
public class AdicionaTopicoComentarios { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; Topico topico = new Topico () ; topico . setTitulo ( " K19 - Orphan Removal " ) ; for ( int i = ; i < 1 ; i ++) { Comentario comentario = new Comentario () ; comentario . setData ( Calendar . getInstance () ) ; topico . getComentarios () . add ( comentario ) ; } manager . getTransaction () . begin () ; manager . persist ( topico ) ; manager . getTransaction () . commit () ; factory . close () ; } }
64
www.k19.com.br
65
E NTITY M ANAGER
Execute a classe AdicionaTopicoComentarios. Consulte os dados das tabelas Topico, Comentario e Topico_Comentario atravs do MySQL Workbench.
31
Desfaa o vnculo entre o tpico e os comentrios adicionados anteriormente. Para isso, crie uma classe chamada TesteOrphanRemoval no pacote br.com.k19.testes do projeto K19-EntityManager.
32
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
public class TesteOrphanRemoval { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Topico topico = manager . find ( Topico . class , 1 L ) ; topico . getComentarios () . clear () ; manager . getTransaction () . commit () ; factory . close () ; } }
Cdigo Java 3.60: TesteOrphanRemoval.java
Consulte os dados das tabelas Topico, Comentario e Topico_Comentario atravs do MySQL Workbench. Observe que os comentrios ainda esto persistidos na tabela Comentario. Apenas os vnculos entre o tpico e os comentrios foram desfeitos. Verique a tabela Topico_Comentario.
33 34 35
Execute novamente a classe AdicionaTopicoComentarios e consulte os dados das tabelas Topico, Comentario e Topico_Comentario atravs do MySQL Workbench. Altere a classe Topico para aplicar o orphanRemoval=true no relacionamento entre tpicos e comentrios.
36
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Topico { @Id @GeneratedValue private Long id ; @OneToMany ( cascade ={ CascadeType . PERSIST } , orphanRemoval = true ) private List < Comentario > comentarios ; private String titulo ; // GETTERS E SETTERS }
Cdigo Java 3.61: Topico.java
Execute novamente a classe TesteOrphanRemoval e consulte os dados das tabelas Topico, Comentario e Topico_Comentario atravs do MySQL Workbench. Observe que agora os comentrios foram apagados da tabela Comentario.
37
www.k19.com.br
65
E NTITY M ANAGER
66
Callbacks
Podemos monitorar o ciclo de vida dos objetos das entidades da nossa aplicao. Determinados eventos podem ser capturados e podemos associar mtodos a esses eventos. Esses mtodos so chamados de callbacks. Um mtodo de callback executado automaticamente quando o evento associado a ele disparado. Veja os eventos que podem ser monitorados na listagem abaixo:
PrePersist: Disparado quando um objeto novo persistido atravs da operao persist() ou merge() dos Entity Managers. Esse evento tambm disparado para os objetos persistidos em cascata. PostPersist: Disparado durante a execuo de uma sincronizao, aps a operao insert correspondente ao objeto que foi persistido. Um rollback na trasano corrente pode desfazer a operao insert, mas no o evento. PreRemove: Disparado quando um objeto gerenciado removido atravs da operao remove() dos Entity Managers. Esse evento tambm disparado para os objetos removidos em cascata. PostRemove: Disparado durante a execuo de uma sincronizao, aps a operao delete correspondente ao objeto que foi removido. Um rollback na transao corrente pode desfazer a operao delete, mas no o evento. PreUpdate: Disparado durante a execuo de uma sincronizao, antes da operao update correspondente ao objeto que foi alterado. PostUpdate: Disparado durante a execuo de uma sincronizao, aps a operao update correspondente ao objeto que foi alterado. Um rollback na transano corrente pode desfazer a operao update, mas no o evento. PostLoad: Disparado depois que uma instncia de uma entidade foi carregada com os dados do banco de dados.
Os mtodos de callback associados aos eventos acima listados podem ser denidos nas classes das entidades da nossa aplicao. Esses mtodos devem ser anotados com @PrePersist, @PostPersist, @PreRemove, @PostRemove, @PreUpdate, @PostUpdate ou @PostLoad para associ-los aos eventos correspondentes. No exemplo abaixo, adicionamos um mtodo de callback para cada evento denido pela especicao JPA.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 @Entity public class Produto { @Id @GeneratedValue private Long id ; private String nome ; private Double preco ;
@PrePersist public void prePersist () { System . out . println ( " Persistindo um novo objeto com persist () ou merge () ... " ) ; } @PostPersist
66
www.k19.com.br
67
18 19 2 21 22 23 24 25 26 27 28 29 3 31 32 33 34 35 36 37 38 39 4 41 42 43 44 45 46 47 48 49
E NTITY M ANAGER
public void postPersist () { System . out . println ( " O comando insert foi executado no banco de dados ... " ) ; System . out . println ( " Um rollback ainda pode desfazer o comando insert ... " ) ; } @PreRemove public void preRemove () { System . out . println ( " Removendo um objeto gerenciado com remove () ... " ) ; } @PostRemove public void postRemove () { System . out . println ( " O comando delete foi executado no banco de dados ... " ) ; System . out . println ( " Um rollback ainda pode desfazer o comando delete ... " ) ; } @PreUpdate public void preUpdate () { System . out . println ( " O comando update executar no banco de dados ... " ) ; } @PostUpdate public void postUpdate () { System . out . println ( " O comando update foi executado no banco de dados ... " ) ; System . out . println ( " Um rollback ainda pode desfazer o comando update ... " ) ; } @PostLoad public void postLoad () { System . out . println ( " Um objeto foi carregado com os dados do banco de dados . " ) ; } }
Cdigo Java 3.62: Produto.java
Mais Sobre
Um mesmo mtodo de callback pode estar associado a dois ou mais eventos. No exemplo abaixo, o mtodo callback() foi associado a todos os eventos JPA.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 @Entity public class Produto { @Id @GeneratedValue private Long id ; private String nome ; private Double preco ; @PrePersist @PostPersist @PreRemove @PostRemove @PreUpdate @PostUpdate @PostLoad public void callback () { System . out . println ( " tratando todos os eventos " ) ; } }
Cdigo Java 3.63: Produto.java
www.k19.com.br
67
E NTITY M ANAGER
68
Mais Sobre
Podemos reaproveitar mtodos de callback para duas ou mais entidades. Para isso, devemos deni-los em uma classe separada e depois associar essa classe s entidades desejadas atravs da anotao @EntityListeners.
1 2 3 4 5 6 7 8 9 1 11 12 public class K19Listener { @PrePersist @PostPersist @PreRemove @PostRemove @PreUpdate @PostUpdate @PostLoad public void callback () { System . out . println ( " tratando todos os eventos " ) ; } }
Cdigo Java 3.64: K19Listener.java
1 2 3 4 5 6 7 8 9 1 11
@Entity @EntityListeners ( K19Listener . class ) public class Produto { @Id @GeneratedValue private Long id ; private String nome ; private Double preco ; }
Cdigo Java 3.65: Produto.java
Exerccios de Fixao
38
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21
68
www.k19.com.br
69
22 23 // GETTERS E SETTERS }
Cdigo Java 3.66: Produto.java
E NTITY M ANAGER
Adicione alguns produtos no banco de dados. Crie uma classe chamada AdicionaProduto no pacote br.com.k19.testes do projeto K19-EntityManager.
39
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class AdicionaProduto { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; Produto p = new Produto () ; p . setNome ( " K19 - Caneta " ) ; p . setPreco (4.56) ; manager . getTransaction () . begin () ; manager . persist ( p ) ; manager . getTransaction () . commit () ; factory . close () ; } }
Cdigo Java 3.67: AdicionaProduto.java
Concorrncia
Quando dois Entity Managers manipulam objetos da mesma entidade e com o mesmo identicador, um resultado incorreto pode ser obtido. Por exemplo, suponha que os seguintes trechos de cdigo sejam executados em paralelo.
1 2 3 4 5 6 7 manager1 . getTransaction () . begin () ; Conta x = manager1 . find ( Conta . class , 1 L ) ; x . setSaldo ( x . getSaldo () + 5 );
1 2 3 4 5 6 7
manager2 . getTransaction () . begin () ; Conta y = manager2 . find ( Conta . class , 1 L ) ; y . setSaldo ( y . getSaldo () - 5 );
www.k19.com.br
69
E NTITY M ANAGER
70
O primeiro trecho acrescenta 500 reais ao saldo da conta com identicador 1. O segundo trecho retira 500 reais da mesma conta. Dessa forma, o saldo dessa conta deve possuir o mesmo valor antes e depois desses dois trechos de cdigo serem executados. Contudo, dependendo da ordem na qual as linhas dos dois trechos so executadas, o resultado pode ser outro. Por exemplo, suponha que o valor inicial do saldo da conta com identicador 1 seja 2000 reais e as linhas dos dois trechos so executadas na seguinte ordem:
1 2 3 4 5 6 7 8 9 1 11 12 13 manager1 . getTransaction () . begin () ; manager2 . getTransaction () . begin () ; Conta x = manager1 . find ( Conta . class , 1 L ) ; // x : saldo = 2 x . setSaldo ( x . getSaldo () + 5 ) ; // x : saldo = 25
manager1 . getTransaction () . commit () ; // Conta 1: saldo = 25 manager2 . getTransaction () . commit () ; // Conta 1: saldo = 15
Exerccios de Fixao
Acrescente no pacote br.com.k19.modelo do projeto K19-EntityManager uma classe para denir contas bancrias.
40
1 2 3 4 5 6 7 8 9 1 11
@Entity public class Conta { @Id @GeneratedValue private Long id ; private double saldo ; // GETTERS AND SETTERS }
Cdigo Java 3.71: Conta.java
Adicione uma classe no pacote br.com.k19.testes para cadastrar uma conta no banco de dados.
41
1 2 3 4 5 6 7 8 9 1 11 12 13
public class AdicionaConta { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Conta c = new Conta () ; c . setSaldo (2 ); manager . persist ( c ) ; manager . getTransaction () . commit () ;
70
www.k19.com.br
71
14 15 16 17 18
E NTITY M ANAGER
Execute e verique a tabela Conta. Simule o problema de concorrncia entre Entity Managers adicionando a seguinte classe no pacote br.com.k19.testes.
42
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27
public class TestaAcessoConcorrente { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager1 = factory . createEntityManager () ; EntityManager manager2 = factory . createEntityManager () ; manager1 . getTransaction () . begin () ; manager2 . getTransaction () . begin () ; Conta conta1 = manager1 . find ( Conta . class , 1 L ) ; conta1 . setSaldo ( conta1 . getSaldo () + 5 );
Conta conta2 = manager2 . find ( Conta . class , 1 L ) ; conta2 . setSaldo ( conta2 . getSaldo () - 5 manager1 . getTransaction () . commit () ; manager2 . getTransaction () . commit () ; manager1 . close () ; manager2 . close () ; factory . close () ; } }
Cdigo Java 3.73: TestaAcessoConcorrente.java
);
Execute e verique que o saldo nal da conta com identicador 1 1500, mas o correto seria 2000.
Locking Otimista
Para solucionar o problema da concorrncia entre Entity Managers, podemos aplicar a idia de Locking Otimista. Nessa abordagem, um atributo para determinar a verso dos registros acrescentado na entidade. Esse atributo deve ser anotado com @Version e seu tipo deve ser short, int, long, Short, Integer, Long ou java.sql.Timestamp.
1 2 3 4 5 6 7 8 @Entity public class Conta { @Id @GeneratedValue private Long id ; private double saldo ;
www.k19.com.br
71
E NTITY M ANAGER
9 1 11 12 13 14
72
Toda vez que um Entity Manager modica um registro da tabela correspondente classe Conta, o campo referente ao atributo anotado com @Version atualizado. Agora, antes de modicar um registro da tabela referente classe Conta, os Entity Managers comparam a verso do registro no banco de dados com a do objeto que eles possuem. Se as verses forem a mesma, signica que nenhum outro Entity Manager modicou o registro e ento as modicaes podem ser executadas sem problemas. Caso contrrio, se as verses forem diferentes, signica que algum outro Entity Manager modicou o registro e ento as modicaes so abortadas e uma exceo lanada. Em geral, as aplicaes devem capturar essa exceo e tentar refazer a operao.
Exerccios de Fixao
43
1 2 3 4 5 6 7 8 9 1 11 12 13 14
44 45 46
Apague a tabela Conta atravs do MySQL Workbench. Execute a classe AdicionaConta e verique a tabela Conta atravs do MySQL Workbench.
Execute a classe TestaAcessoConcorrente e observe a exceo gerada pelo segundo Entity Manager.
Locking Pessimista
Outra abordagem para lidar com o problema da concorrncia entre Entity Managers o Locking Pessimista. Nessa abordagem, um Entity Manager pode travar os registros, fazendo com que os outros Entity Managers que desejem manipular os mesmos registros tenham que aguardar.
72
www.k19.com.br
73
E NTITY M ANAGER
H vrias maneiras de utilizar o locking pessimista. Uma delas passar mais um parmetro quando um objeto buscado atravs do mtodo find().
1 Conta x = manager . find ( Conta . class , 1L , LockModeType . PESSIMISTIC_WRITE ) ;
Uma grande diculdade em utilizar locking pessimista que podemos gerar um deadlock. Suponha que dois Entity Managers busquem o mesmo objeto na mesma thread utilizando o locking pessimista como mostra o cdigo a seguir.
1 2 3 Conta x = manager1 . find ( Conta . class , 1L , LockModeType . PESSIMISTIC_WRITE ) ; Conta y = manager2 . find ( Conta . class , 1L , LockModeType . PESSIMISTIC_WRITE ) ; manager1 . commit () ; // NUNCA VAI EXECUTAR ESSA LINHA
Na linha 1, o primeiro Entity Manager trava a conta com identicador 1 e esse objeto s ser liberado na linha 3. Na linha 2, o segundo Entity Manager vai esperar o primeiro liberar o objeto, impedindo que a linha 3 seja executada. Dessa forma, a linha 3 nunca ser executada. Depois de um certo tempo esperando na linha 2, o segundo Entity Manager lana uma exceo.
Exerccios de Fixao
Teste o problema de deadlock quando o locking pessimista utilizado. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-EntityManager.
47
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25
public class TestaDeadLock { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager_pu " ) ; EntityManager manager1 = factory . createEntityManager () ; EntityManager manager2 = factory . createEntityManager () ; manager1 . getTransaction () . begin () ; manager2 . getTransaction () . begin () ; manager1 . find ( Produto . class , 1L , LockModeType . PESSIMISTIC_WRITE ) ; System . out . println ( " Produto 1 travado " ) ; manager2 . find ( Produto . class , 1L , LockModeType . PESSIMISTIC_WRITE ) ; System . out . println ( " Essa mensagem no ser impressa !!! " ) ; manager1 . getTransaction () . commit () ; manager2 . getTransaction () . commit () ; manager1 . close () ; manager2 . close () ; factory . close () ; } }
Cdigo Java 3.78: TestaDeadLock.java
www.k19.com.br
73
E NTITY M ANAGER
74
74
www.k19.com.br
CAPTULO
JPQL
A capacidade que os bancos de dados possuem para realizar consultas de maneira eciente um forte argumento para utiliz-los. A denio e os resultados das consultas nos banco de dados so fortemente baseados no modelo relacional. Por outro lado, natural que as aplicaes baseadas no modelo orientado a objetos desejem que a denio e os resultados das consultas sejam baseados no paradigma orientado a objetos. Por isso, os provedores de JPA oferecem mecanismos para realizar consultas de uma maneira orientada a objetos. Para ser mais exato, a especicao JPA 2 dene dois mecanismos para realizar consultas orientadas a objetos: o primeiro utiliza uma linguagem especca para consultas chamada JPQL (Java Persistence Query Language) e o segundo basicamente uma biblioteca Java para consultas. Outro fator fundamental para justicar a utilizao dos mecanismos de consulta do JPA 2 que eles so independentes dos mecanismos especcos de consulta do banco de dados. Podemos denir uma consulta em JPQL ou Criteria e execut-la em qualquer banco de dados suportado pelo provedor JPA. Neste captulo, mostraremos o funcionamento da JPQL.
Consultas Dinmicas
Consultas em JPQL podem ser denidas em qualquer classe Java, dentro de um mtodo por exemplo. Para criar uma consulta, devemos utilizar o mtodo createQuery() passando uma string com o cdigo JPQL. Consultas criadas dessa maneira so chamadas de consultas dinmicas.
1 2 3 4 public void umMetodoQualquer () { String jpql = " SELECT p FROM Pessoa p " ; Query query = manager . createQuery ( jpql ) ; }
Apesar da exibilidade, criar consultas dinmicas pode prejudicar a performance da aplicao. Por exemplo, se uma consulta dinmica criada dentro de um mtodo toda vez que esse mtodo for chamado, o cdigo JPQL dessa consulta ser processado pelo provedor. Uma alternativa s consultas dinmicas so as Named Queries, que so menos exveis porm mais ecientes.
Named Query
Diferentemente de uma consulta dinmica, uma Named Query processada apenas no momento da inicializao da unidade de persistncia. Alm disso, os provedores JPA podem mapear as Named Queries para Stored Procedures pre-compiladas no banco de dados melhorando a performance das consultas.
www.k19.com.br
75
JPQL
76
As Named Queries so denidas atravs de anotaes nas classes que implementam as entidades. Podemos aplicar a anotao @NamedQuery quando queremos denir apenas uma consulta ou a anotao @NamedQueries quando queremos denir vrias consultas.
1 2 3 4 @NamedQuery ( name = " Pessoa . findAll " , query = " SELECT p FROM Pessoa p " ) class Pessoa { ... }
Cdigo Java 4.2: Pessoa.java
1 2 3 4 5 6 7
@NamedQueries ({ @NamedQuery ( name = " Pessoa . findAll " , query = " SELECT p FROM Pessoa p " ) , @NamedQuery ( name = " Pessoa . count " , query = " SELECT COUNT ( p ) FROM Pessoa p " ) }) class Pessoa { ... }
Cdigo Java 4.3: Pessoa.java
Mais Sobre
O nome de uma Named Query deve ser nico na unidade de persistncia. Para evitar nomes repetidos, uma boa prtica utilizar o nome de uma entidade como prexo para o nome da consulta. Em geral, a entidade escolhida a que tem maior relao com a consulta. Veja o exemplo abaixo.
1 @NamedQuery ( name = " Pessoa . findAll " , query = " SELECT p FROM Pessoa p " )
Para executar uma Named Query, devemos utilizar o mtodo createNamedQuery(). Apesar do nome, esse mtodo no cria uma Named Query, pois as Named Queries so criadas na inicializao da unidade de persistncia. Esse mtodo apenas recupera uma Named Query existente para ser utilizada.
1 2 3 4 public void listaPessoas () { Query query = manager . createNamedQuery ( " Pessoa . findAll " ) ; List < Pessoa > pessoas = query . getResultList () ; }
Cdigo Java 4.5: Recuperando uma Named Query
Parmetros
Para tornar as consultas em JPQL mais genricas e evitar problemas com SQL Injection, devemos parametriz-las. Adicionar um parmetro em uma consulta simples. Para isso, basta utilizar caractere : seguido do nome do argumento.
1 2 @NamedQuery ( name = " Pessoa . findByIdade " , query = " SELECT p FROM Pessoa p WHERE p . idade > : idade " )
Cdigo Java 4.6: Parametrizando uma consulta
76
www.k19.com.br
77
JPQL
Antes de executar uma consulta com parmetros, devemos denir os valores dos argumentos.
1 2 3 4 5 public void listaPessoas () { Query query = manager . createNamedQuery ( " Pessoa . findByIdade " ) ; query . setParameter ( " idade " , 18) ; List < Pessoa > pessoasComMaisDe18 = query . getResultList () ; }
possvel tambm adicionar parmetros em uma consulta de maneira ordinal com o uso do caractere ? seguido de um nmero.
1 2 @NamedQuery ( name = " Pessoa . findByIdade " , query = " SELECT p FROM Pessoa p WHERE p . idade > ?1 " )
1 2 3 4 5
public void listaPessoas () { Query query = manager . createNamedQuery ( " Pessoa . findByIdade " ) ; query . setParameter (1 , 18) ; List < Pessoa > pessoasComMaisDe18 = query . getResultList () ; }
Exerccios de Fixao
Crie um projeto no eclipse chamado K19-JPQL. Copie a pasta lib do projeto K19-JPA2-Hibernate para o projeto K19-JPQL. Depois adicione os jars dessa pasta no classpath desse novo projeto.
1 2 Abra o MySQL Workbench e apague a base de dados K21_jpql_bd se existir. Depois crie a base de dados K21_jpql_bd. 3 Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-JPQL. Altere o arquivo persistence.xml do projeto K19-JPQL, modicando os nomes da uni-
www.k19.com.br
77
JPQL
4
78
ses:
1 2 3 4 5 6 7 8 9 1 11 12 @Entity public class Livro { @Id @GeneratedValue private Long id ; private String nome ; private Double preco ; // GETTERS E SETTERS }
Cdigo Java 4.10: Livro.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Autor { @Id @GeneratedValue private Long id ; private String nome ; @ManyToMany private Collection < Livro > livros = new ArrayList < Livro >() ; // GETTERS E SETTERS }
Cdigo Java 4.11: Autor.java
Carregue o banco de dados com as informaes de alguns livros e autores. Adicione a seguinte classe em um novo pacote chamado br.com.k19.testes dentro do projeto K19-JPQL.
5
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28 29
public class PopulaBanco { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Livro livro1 = new Livro () ; livro1 . setNome ( " The Battle for Your Mind " ) ; livro1 . setPreco (2 .6) ; manager . persist ( livro1 ) ; Livro livro2 = new Livro () ; livro2 . setNome ( " Differentiate or Die " ) ; livro2 . setPreco (15.8) ; manager . persist ( livro2 ) ; Livro livro3 = new Livro () ; livro3 . setNome ( " How to Transform Your Ideas " ) ; livro3 . setPreco (32.7) ; manager . persist ( livro3 ) ; Livro livro4 = new Livro () ; livro4 . setNome ( " Digital Fortress " ) ; livro4 . setPreco (12.9) ; manager . persist ( livro4 ) ; Livro livro5 = new Livro () ;
78
www.k19.com.br
79
3 31 32 33 34 35 36 37 38 39 4 41 42 43 44 45 46 47 48 49 5 51 52 53 54 55 56 57 58 59 6 61 62 63 64 65 66 67 68 69 livro5 . setNome ( " Marketing in an Era of Competition , Change and Crisis " ) ; livro5 . setPreco (26.8) ; manager . persist ( livro5 ) ; Autor autor1 = new Autor () ; autor1 . setNome ( " Patrick Cullen " ) ; autor1 . getLivros () . add ( livro2 ) ; autor1 . getLivros () . add ( livro4 ) ; manager . persist ( autor1 ) ; Autor autor2 = new Autor () ; autor2 . setNome ( " Fraser Seitel " ) ; autor2 . getLivros () . add ( livro3 ) ; manager . persist ( autor2 ) ; Autor autor3 = new Autor () ; autor3 . setNome ( " Al Ries " ) ; autor3 . getLivros () . add ( livro1 ) ; manager . persist ( autor3 ) ; Autor autor4 = new Autor () ; autor4 . setNome ( " Jack Trout " ) ; autor4 . getLivros () . add ( livro1 ) ; autor4 . getLivros () . add ( livro2 ) ; autor4 . getLivros () . add ( livro5 ) ; manager . persist ( autor4 ) ; Autor autor5 = new Autor () ; autor5 . setNome ( " Steve Rivkin " ) ; autor5 . getLivros () . add ( livro2 ) ; autor5 . getLivros () . add ( livro3 ) ; autor5 . getLivros () . add ( livro5 ) ; manager . persist ( autor5 ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 4.12: PopulaBanco.java
JPQL
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class TesteConsultaDinamicas { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " select a from Autor a " ) ; List < Autor > autores = query . getResultList () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; Collection < Livro > livros = autor . getLivros () ; for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; System . out . println ( " Preo : " + livro . getPreco () ) ; System . out . println () ; } System . out . println () ; }
www.k19.com.br
79
JPQL
21 22 23 24 25
80
Execute e observe que as consultas so realizadas aos poucos devido ao carregamento em modo LAZY.
7
1 2 3 4 5
Em seguida, crie um teste para Named Query denida no exerccio anterior. Adicione no pacote br.com.k19.testes do projeto K19-JPQL a seguinte classe:
8
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25
public class TesteNamedQuery { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createNamedQuery ( " Autor . findAll " ) ; List < Autor > autores = query . getResultList () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; Collection < Livro > livros = autor . getLivros () ; for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; System . out . println ( " Preo : " + livro . getPreco () ) ; System . out . println () ; } System . out . println () ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.15: TesteNamedQuery
Execute e observe que as consultas so realizadas aos poucos devido ao carregamento em modo LAZY. Acrescente a anotao @NamedQuery na classe Livro para denir uma consulta por preo mnimo utilizando parmetros.
9
1 2 3 4 5
@Entity @NamedQuery ( name = " Livro . findByPrecoMinimo " , query = " select livro from Livro livro where livro . preco >= : preco " ) public class Livro { ...
80
www.k19.com.br
81
6 }
JPQL
10
Em seguida, crie um teste para Named Query denida no exerccio anterior. Adicione no pacote
Tipos de Resultado
Lista de Entidades
Uma consulta em JPQL pode devolver uma lista com os objetos de uma entidade que so compatveis com os ltros da pesquisa. Por exemplo, considere a seguinte consulta:
1 String query = " SELECT p FROM Pessoa p " ;
O resultado dessa pesquisa uma lista com todas as instncias da entidade Pessoa que foram persistidas. Esse resultado pode ser obtido atravs do mtodo getResultList().
1 2 3 String query = " SELECT p FROM Pessoa p " ; Query query = manager . createQuery ( query ) ; List < Pessoa > pessoas = query . getResultList () ;
Nesse caso, os objetos da listagem devolvida pela consulta esto no estado managed, ou seja, alteraes realizadas no contedo desses objetos so sincronizadas com o banco de dados de acordo com as regras de sincronizao.
www.k19.com.br
81
JPQL
82
Typed Query
O compilador da linguagem Java no verica a compatibilidade entre a varivel e o resultado da consulta. Na consulta abaixo, o compilador no sabe se o mtodo getResultList() devolver de fato uma lista de pessoas, pois ele no processa a string que dene a consulta.
1 2 3 String query = " SELECT p FROM Pessoa p " ; Query query = manager . createQuery ( query ) ; List < Pessoa > pessoas = query . getResultList () ;
Sem a ajuda do compilador, h mais chances de ocorrerem erros de execuo. Por exemplo, a consulta abaixo provocaria uma exceo.
1 2 3 String query = " SELECT p FROM Pessoa p " ; Query query = manager . createQuery ( query ) ; List < Departamento > departamentos = query . getResultList () ;
Para diminuir a chance de erro, podemos utilizar as Typed Queries. Nesse tipo de consulta, o compilador tambm no verica o cdigo JPQL. No entanto, devemos especicar o tipo de resultado esperado para que o compilador verique o restante do cdigo e garanta que a utilizao do resultado da consulta seja compatvel com o tipo especicado.
1 2 3 String query = " SELECT p FROM Pessoa p " ; TypedQuery < Pessoa > query = manager . createQuery ( query , Pessoa . class ) ; List < Pessoa > pessoas = query . getResultList () ;
Dessa forma, teramos acesso a todos os dados das pessoas dessa listagem. Contudo, muitas vezes, no desejamos todas as informaes. Por exemplo, se a nossa aplicao precisa apresentar uma lista dos nomes das pessoas cadastradas, no necessrio recuperar nada alm dos nomes. Quando denimos as consultas, podemos determinar o que elas devem trazer de fato do banco de dados. Por exemplo, a consulta abaixo recupera apenas os nomes das pessoas.
1 2 3 String query = " SELECT p . nome FROM Pessoa p " ; TypedQuery < String > query = manager . createQuery ( query , String . class ) ; List < String > nomes = query . getResultList () ;
Cdigo Java 4.24: Recuperando apenas os nomes das pessoas
82
www.k19.com.br
83
JPQL
Valores nicos
Suponha que desejamos saber quantas pessoas possuem mais do que 18 anos. Nesse caso, no necessrio trazer mais do que um nmero do banco de dados. Em outras palavras, o resultado dessa consulta no deve ser uma lista, mas sim um valor numrico. Para isso, podemos aplicar as funes de agregao: AVG COUNT MAX MIN SUM Calcula a mdia de um conjunto de nmeros Contabiliza o nmero de resultados Recupera o maior elemento um conjunto de nmeros Recupera o menor elemento um conjunto de nmeros Calcula a soma de um conjunto de nmeros
Tabela 4.1: Funes de agregao
A consulta abaixo devolve a quantidade de pessoas persistidas. Observe que isso feito utilizandose o mtodo getSingleResult() ao invs do getResultList(), pois o resultado no uma lista.
1 2 3 String query = " SELECT COUNT ( p ) FROM Pessoa p " ; TypedQuery < Long > query = manager . createQuery ( query , Long . class ) ; Long numeroDePessoas = query . getSingleResult () ;
Cdigo Java 4.25: Recuperando o nmero de pessoas persistidas
Resultados Especiais
Algumas consultas possuem resultados complexos. Por exemplo, suponha que desejamos obter uma listagem com os nomes dos funcionrios e o nome do departamento em que o funcionrio trabalha.
1 " SELECT f . nome , f . departamento . nome FROM Funcionario f " ;
Nesse caso, o resultado ser uma lista de array de Object. Para manipular essa lista, devemos lidar com o posicionamento dos dados nos arrays.
1 2 3 4 5 6 7 8 String query = " SELECT f . nome , f . departamento . nome FROM Funcionario f " ; Query query = manager . createQuery ( query ) ; List < Object [] > lista = query . getResultList () ; for ( Object [] tupla : lista ) { System . out . println ( " Funcionrio : " + tupla [ ]) ; System . out . println ( " Departamento : " + tupla [1]) ; }
www.k19.com.br
83
JPQL
84
Operador NEW
Para contornar a diculdade de lidar com o posicionamento dos dados nos arrays, podemos criar uma classe para modelar o resultado da nossa consulta e aplicar o operador NEW no cdigo JPQL.
1 2 3 4 5 6 7 8 9 1 11 12 13 package resultado ; class FuncionarioDepartamento { private String funcionarioNome ; private String departamentoNome ; public FuncionarioDepartamento ( String funcionarioNome , String departamentoNome ) { this . funcionarioNome = funcionarioNome ; this . departamentoNome = departamentoNome ; } // GETTERS E SETTERS }
Cdigo Java 4.29: FuncionarioDepartamento.java
1 2 3 4 5 6 7 8 9 1 11
String query = " SELECT NEW resultado . FuncionarioDepartamento ( f . nome , f . departamento . nome ) FROM Funcionario f " ; Query < FuncionarioDepartamento > query = manager . createQuery ( query ) ; List < FuncionarioDepartamento > resultados = query . getResultList () ; for ( FuncionarioDepartamento resultado : resultados ) { System . out . println ( " Funcionrio : " + resultado . getFuncionarioNome () ) ; System . out . println ( " Departamento : " + resultado . getDepartamentoNome () ) ; }
A vantagem da utilizao de uma classe para modelar o resultado de uma consulta complexa ao invs de um array de Object que a aplicao no precisa lidar com o posicionamento dos itens do resultado.
Importante
A classe que modela o resultado complexo esperado de uma consulta deve possuir um construtor para receber os dados do resultado.
Importante
Para utilizar uma classe que modela o resultado de uma consulta complexa dentro do cdigo JPQL com o operador NEW, devemos indicar o nome completo da classe (fully qualied name).
Exerccios de Fixao
11
Teste o recurso de Typed Query utilizando a Named Query Autor.findAll. Adicione no pacote
84
www.k19.com.br
85
2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; TypedQuery < Autor > query = manager . createNamedQuery ( " Autor . findAll " , Autor . class ) ; List < Autor > autores = query . getResultList () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.31: TesteTypedQuery.java
JPQL
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
public class TesteConsultaObjetosComuns { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; TypedQuery < String > query = manager . createQuery ( " select livro . nome from Livro livro " , String . class ) ; List < String > nomes = query . getResultList () ; for ( String nome : nomes ) { System . out . println ( nome ) ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.32: TesteConsultaObjetosComuns.java
Crie um teste para recuperar o valor da mdia dos preos dos livros. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-JPQL.
13
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
public class TesteConsultaLivroPrecoMedio { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; TypedQuery < Double > query = manager . createQuery ( " select avg ( livro . preco ) from Livro livro " , Double . class ) ; Double precoMedio = query . getSingleResult () ; System . out . println ( " Preo mdio : " + precoMedio ) ; manager . close () ; factory . close () ; } }
Cdigo Java 4.33: TesteConsultaLivroPrecoMedio.java
www.k19.com.br
85
JPQL
14
86
No pacote br.com.k19.modelo do projeto K19-JPQL, crie duas entidades para modelar departamentos e funcionrios.
1 2 3 4 5 6 7 8 9 1 @Entity public class Departamento { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 4.34: Departamento.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Funcionario { @Id @GeneratedValue private Long id ; private String nome ; @ManyToOne private Departamento departamento ; // GETTERS E SETTERS }
Cdigo Java 4.35: Funcionario.java
Adicione alguns funcionrios e departamentos. No pacote br.com.k19.testes do projeto K19JPQL, adicione a seguinte classe:
15
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25
public class AdicionaFuncionarioDepartamento { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Departamento d = new Departamento () ; d . setNome ( " Treinamentos " ) ; Funcionario f = new Funcionario () ; f . setNome ( " Rafael Cosentino " ) ; f . setDepartamento ( d ) ; manager . persist ( f ) ; manager . persist ( d ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 4.36: AdicionaFuncionarioDepartamento.java
Crie um teste para recuperar os nomes dos funcionrios e os nomes dos seus respectivos departamentos. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-JPQL.
16
86
www.k19.com.br
87
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 public class TesteBuscaFuncionarioDepartamento { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " select f . nome , f . departamento . nome from Funcionario f " ) ; List < Object [] > lista = query . getResultList () ; for ( Object [] tupla : lista ) { System . out . println ( " Funcionrio : " + tupla [ ]) ; System . out . println ( " Departamento : " + tupla [1]) ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.37: TesteBuscaFuncionarioDepartamento.java
JPQL
17 No pacote br.com.k19.modelo do projeto K19-JPQL, crie uma classe para melhorar a manipulao da consulta dos nomes dos funcionrios e nomes dos seus respectivos departamentos.
1 2 3 4 5 6 7 8 9 1 11
public class FuncionarioDepartamento { private String funcionario ; private String departamento ; public FuncionarioDepartamento ( String funcionario , String departamento ) { this . funcionario = funcionario ; this . departamento = departamento ; } // GETTERS }
Cdigo Java 4.38: FuncionarioDepartamento.java
Altere a classe TesteBuscaFuncionarioDepartamento para que ela utilize o operador NEW da JPQL.
18
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class TesteBuscaFuncionarioDepartamento { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " select new br . com . k19 . modelo . FuncionarioDepartamento ( f . nome , f . departamento . nome ) from Funcionario f " ) ; List < FuncionarioDepartamento > lista = query . getResultList () ; for ( FuncionarioDepartamento fd : lista ) { System . out . println ( " Funcionrio : " + fd . getFuncionario () ) ; System . out . println ( " Departamento : " + fd . getDepartamento () ) ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.39: TesteBuscaFuncionarioDepartamento.java
www.k19.com.br
87
JPQL
88
Paginao
Supondo que exista uma grande quantidade de livros cadastrados no banco de dados, buscar todos os livros sem nenhum ltro vai sobrecarregar o trfego da rede e a memria utilizada pela aplicao. Nesses casos, podemos aplicar o conceito de paginao para obter os livros aos poucos. A paginao do resultado de uma consulta realizada atravs dos mtodos setFirstResult() e setMaxResults().
1 2 3 4 TypedQuery < Livro > query = manager . createQuery ( " select livro from Livro livro " , Livro . class ) ; query . setFirstResult (1 ) ; query . setMaxResults (2 ) ; List < Livro > livros = query . getResultList () ;
Cdigo Java 4.40: Denindo a paginao do resultado da consulta
Exerccios de Fixao
Teste o recurso de paginao das consultas. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-JPQL.
19
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21
public class TesteBuscaPaginada { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; TypedQuery < Livro > query = manager . createQuery ( " select livro from Livro livro " , Livro . class ) ; query . setFirstResult (2) ; query . setMaxResults (3) ; List < Livro > livros = query . getResultList () ; for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.41: TesteBuscaPaginada.java
O Problema do N + 1
Em alguns casos, o comportamento LAZY pode gerar um nmero excessivo de consultas, comprometendo o desempenho da aplicao. Por exemplo, considere as entidades Departamento e Funcionario.
1 2 3 @Entity public class Funcionario {
88
www.k19.com.br
89
4 5 6 7 8 9 1 @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 4.42: Funcionario.java
JPQL
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Departamento { @Id @GeneratedValue private Long id ; private String nome ; @OneToMany private List < Funcionario > funcionarios ; // GETTERS E SETTERS }
Cdigo Java 4.43: Departamento.java
Em muitos dos casos, quando buscamos uma lista de departamentos, no precisamos dos dados dos seus respectivos funcionrios. Assim, optamos pelo comportamento LAZY para o relacionamento entre departamentos e funcionrios. No entanto, em alguns casos, estaremos sim interessados nos dados dos departamentos e dos seus funcionrios. Podemos realizar uma consulta para recuperar a lista de departamentos. Alm disso, como o comportamento escolhido foi LAZY, uma consulta adicional ser realizada pelo provedor para cada departamento a m de recuperar os seus funcionrios. No total, teremos N + 1 consultas, onde N o nmero de departamentos obtidos na primeira consulta. Note que se o relacionamento entre departamentos e funcionrios fosse EAGER ento apenas uma consulta seria necessria nesses casos. Para solucionar esse problema, podemos utilizar o comando left join fetch na consulta que buscaria os departamentos.
1 SELECT DISTINCT ( d ) FROM Departamento d LEFT JOIN FETCH d . funcionarios
Aplicando o comando left join fetch, os departamentos e seus respectivos funcionrios so recuperados em apenas uma consulta.
Exerccios de Fixao
20 Faa uma consulta para obter todos os autores e seus respectivos livros. No pacote br.com.k19.testes do projeto K19-Criteria, crie a classe ListaAutoresELivros.
1 2 3 4
public class ListaAutoresELivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ;
www.k19.com.br
89
JPQL
5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " select a from Autor a " ) ; List < Autor > autores = query . getResultList () ; System . out . println () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; Collection < Livro > livros = autor . getLivros () ; for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; } System . out . println () ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.45: ListaAutoresELivros.java
90
Execute e observe, no console, a quantidade de consultas realizadas. Altere a classe ListaAutoresELivros para reduzir a quantidade de consultas ao banco de dados. Aplique o comando fetch join na consulta de autores.
21
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25
public class ListaAutoresELivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " select distinct ( a ) from Autor a left join fetch a . livros " ) ; List < Autor > autores = query . getResultList () ; System . out . println () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; Collection < Livro > livros = autor . getLivros () ; for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; } System . out . println () ; } manager . close () ; factory . close () ; } }
Cdigo Java 4.46: ListaAutoresELivros.java
91
JPQL
modicados ou removidos.
1 2 Pessoa p = manager . find ( Pessoa . class , 1 L ) ; p . setNome ( " Rafael Cosentino " ) ;
1 2
Em alguns casos, essa abordagem no a mais eciente. Por exemplo, suponha que uma aplicao que controla os produtos de uma loja virtual necessite atualizar os preos de todos os produtos com uma taxa xa.
1 2 3 4 5 6 TypedQuery < Produto > query = manager . createNamedQuery ( " Produto . findAll " ) ; List < Produto > produtos = query . getResultList () ; for ( Produto p : produtos ) { double preco = p . getPreco () ; p . setPreco ( preco * 1.1) ; // 1 % de aumento }
Todos os produtos seriam carregados e isso seria sobrecarregaria a rede, pois uma grande quantidade de dados seria transferida do banco de dados para a aplicao, e a memria, pois muitos objetos seriam criados pelo provedor JPA. A abordagem mais eciente nesse caso realizar uma operao em lote (bulk operation). Uma operao em lote executada no banco de dados sem transferir os dados dos registros para a memria da aplicao.
1 2 Query query = manager . createQuery ( " UPDATE Produto p SET p . preco = p . preco * 1.1 " ) ; query . executeUpdate () ;
A mesma estratgia pode ser adotada quando diversos registros devem ser removidos. No necessrio carregar os objetos na memria para remov-los, basta realizar uma operao em lote.
1 2 Query query = manager . createQuery ( " DELETE Produto p WHERE p . preco < 5 " ) ; query . executeUpdate () ;
Exerccios de Fixao
22
1 2 3 4 5 6 7 8 9 1 11 12
www.k19.com.br
91
JPQL
23
92
Adicione alguns produtos no banco de dados. Crie a seguinte classe em um pacote chamado br.com.k19.testes do projeto K19-JPQL.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 public class AdicionaProdutos { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; for ( int i = ; i < 1 ; i ++) { Produto p = new Produto () ; p . setNome ( " produto " + i ) ; p . setPreco ( i * 1 . ) ; manager . persist ( p ) ; } manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 4.53: AdicionaProdutos.java
Faa uma operao em lote para atualizar o preo de todos os produtos de acordo com uma taxa
xa.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 public class AumentaPreco { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Query query = manager . createQuery ( " UPDATE Produto p SET p . preco = p . preco * 1.1 " ) ; query . executeUpdate () ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 4.54: AumentaPreco.java
Execute e verique a tabela produto na base de dados K21_jpql. Observe tambm o console do Eclipse. Nenhum select realizado.
25
Faa uma operao em lote para remover todos os produtos com preo menor do que um valor
xo.
1 2 3 4 public class RemoveProdutos { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu " ) ;
92
www.k19.com.br
93
5 6 7 8 9 1 11 12 13 14 15 16 17 18 EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Query query = manager . createQuery ( " DELETE Produto p WHERE p . preco < 5 " ) ; query . executeUpdate () ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 4.55: RemoveProdutos.java
JPQL
Execute e verique a tabela produto na base de dados K21_jpql. Observe tambm o console do Eclipse. Nenhum select realizado.
Operadores
As consultas em JPQL utilizam alguns tipos de operadores, que veremos a seguir.
Condicionais
Menor (<)
1 String query = " SELECT p FROM Pessoa p WHERE p . idade < : idade " ;
Cdigo Java 4.56: Seleciona as pessoas com idade menor do que a idade especicada
Maior (>)
1 String query = " SELECT p FROM Pessoa p WHERE p . idade > : idade " ;
Cdigo Java 4.57: Seleciona as pessoas com idade maior do que a idade especicada
Igual (=)
1 String query = " SELECT p FROM Pessoa p WHERE p . idade = : idade " ;
Cdigo Java 4.60: Seleciona as pessoas com idade igual a idade especicada
www.k19.com.br
93
JPQL
94
Diferente (<>)
1 String query = " SELECT p FROM Pessoa p WHERE p . idade <> : idade " ;
Cdigo Java 4.61: Seleciona as pessoas com idade diferente da idade especicada
IS NULL
1 String query = " SELECT p FROM Pessoa p WHERE p . nome IS NULL " ;
Cdigo Java 4.62: Seleciona as pessoas cujos nomes so nulos
IS NOT NULL
1 String query = " SELECT p FROM Pessoa p WHERE p . nome IS NOT NULL " ;
Cdigo Java 4.63: Seleciona as pessoas cujos nomes so no nulos
BETWEEN
1 String query = " SELECT p FROM Pessoa p WHERE p . idade BETWEEN : minimo AND : maximo " ;
Cdigo Java 4.64: Seleciona as pessoas cujas idades esto no intervalo especicado
NOT BETWEEN
1 String query = " SELECT p FROM Pessoa p WHERE p . idade NOT BETWEEN : minimo AND : maximo " ;
Cdigo Java 4.65: Seleciona as pessoas cujas idades esto fora do intervalo especicado
AND
1 String query = " SELECT p FROM Pessoa p WHERE p . nome IS NOT NULL AND p . idade >= : idade " ;
Cdigo Java 4.66: Seleciona as pessoas cujas nomes so no nulos e cujas idades so maiores do que a idade especicada
OR
1 String query = " SELECT p FROM Pessoa p WHERE p . nome IS NOT NULL OR p . idade >= : idade " ;
Cdigo Java 4.67: Seleciona as pessoas cujas nomes so no nulos ou cujas idades so maiores do que a idade especicada
NOT
1 String query = " SELECT p FROM Pessoa p WHERE NOT ( p . idade >= : idade ) " ;
Cdigo Java 4.68: Seleciona as pessoas com idade menor do que a idade especicada
MEMBER OF
1 String query = " SELECT f FROM Funcionario f WHERE f MEMBER OF f . empresa . diretoria " ;
Cdigo Java 4.69: Seleciona os funcionrios que fazem parte da diretoria da empresa
NOT MEMBER OF
94
www.k19.com.br
95
1
JPQL
String query = " SELECT f FROM Funcionario f WHERE f NOT MEMBER OF f . empresa . diretoria " ;
Cdigo Java 4.70: Seleciona os funcionrios que no fazem parte da diretoria da empresa
IS EMPTY
1 String query = " SELECT a FROM Autor a WHERE a . livros IS EMPTY " ;
Cdigo Java 4.71: Seleciona os autores que possuem no possuem nenhum livro
IS NOT EMPTY
1 String query = " SELECT a FROM Autor a WHERE a . livros IS NOT EMPTY " ;
Cdigo Java 4.72: Seleciona os autores que possuem possuem ao menos um livro
EXISTS
1 2 String query = " SELECT d FROM Departamento d WHERE EXISTS ( SELECT f FROM FUNCIONARIO f WHERE f . departamento = d ) " ;
Cdigo Java 4.73: Seleciona os departamentos que possuem ao menos um funcionrio
NOT EXISTS
1 2 String query = " SELECT d FROM Departamento d WHERE NOT EXISTS ( SELECT f FROM FUNCIONARIO f WHERE f . departamento = d ) " ;
Cdigo Java 4.74: Seleciona os departamentos que no possuem nenhum um funcionrio
LIKE
1 String query = " SELECT a FROM Autor a WHERE a . nome LIKE Patrick % " ;
Cdigo Java 4.75: Seleciona os autores com nome dentro do padro especicado
NOT LIKE
1 String query = " SELECT a FROM Autor a WHERE a . nome NOT LIKE Patrick % " ;
Cdigo Java 4.76: Seleciona os autores com nome fora do padro especicado
IN
1 String query = " SELECT a FROM Autor a WHERE a . nome IN ( Patrick Cullen , Fraser Seitel ) " ;
Cdigo Java 4.77: Seleciona os autores com nome igual a um dos nomes especicados
NOT IN
1 2 String query = " SELECT a FROM Autor a WHERE a . nome NOT IN ( Patrick Cullen , Fraser Seitel ) " ;
Cdigo Java 4.78: Seleciona os autores com nome diferente dos nomes especicados
www.k19.com.br
95
JPQL
96
Escalares
ALL
1 2 String query = " SELECT livro FROM Livro livro WHERE livro . preco >= ALL ( SELECT livro . preco FROM Livro livro ) " ;
Cdigo Java 4.79: Seleciona os livros mais caros
ANY
1 2 String query = " SELECT livro FROM Livro livro WHERE livro . titulo = ANY ( SELECT livro2 . titulo FROM Livro livro2 WHERE livro <> livro2 ) " ;
Cdigo Java 4.80: Seleciona os livros que possuem ttulos em comum
SOME
1 2 String query = " SELECT livro FROM Livro livro WHERE livro . titulo = SOME ( SELECT livro2 . titulo FROM Livro livro2 WHERE livro <> livro2 ) " ;
Cdigo Java 4.81: Seleciona os livros que possuem ttulos em comum
Agregadores
AVG
1 String query = " SELECT AVG ( livro . preco ) FROM Livro livro " ;
Cdigo Java 4.82: Seleciona a mdia dos preos dos livros
SUM
1 String query = " SELECT SUM ( livro . preco ) FROM Livro livro " ;
Cdigo Java 4.83: Seleciona a soma dos preos dos livros
MIN
1 String query = " SELECT MIN ( livro . preco ) FROM Livro livro " ;
Cdigo Java 4.84: Seleciona o preo do livro mais barato
MAX
1 String query = " SELECT MAX ( livro . preco ) FROM Livro livro " ;
Cdigo Java 4.85: Seleciona o preo do livro mais caro
COUNT
1 String query = " SELECT COUNT ( livro ) FROM Livro livro " ;
Cdigo Java 4.86: Seleciona a quantidade de livros cadastrados
96
www.k19.com.br
97
JPQL
Funes
ABS: Calcula o valor absoluto de um nmero. CONCAT: Concatena strings. CURRENT_DATE: Recupera a data atual. CURRENT_TIME: Recupera o horrio atual. CURRENT_TIMESTAMP: Recupera a data e o horrio atuais. LENGTH: Calcula o nmero de caracteres de uma string. LOCATE: Localiza uma string dentro de outra. LOWER: Deixa as letras de uma string minsculas. MOD: Calcula o resto da diviso entre dois nmeros. SIZE: Calcula o nmero de elementos de uma coleo. SQRT: Calcula a raiz quadrada de um nmero. SUBSTRING: Recupera um trecho de uma string. UPPER: Deixa as letras de uma string maisculas. TRIM: Elimina eventuais espaos no incio e no m de uma string.
ORDER BY
Podemos ordenar o resultado de uma consulta atravs do operador ORDER BY com as opes ASC ou DESC.
1 String query = " SELECT livro FROM Livro livro ORDER BY livro . preco ASC " ;
Exemplos
1. Suponha que seja necessrio selecionar os livros mais baratos. Em outras palavras, devemos selecionar os livros tais que no exista nenhum outro livro com preo menor.
1 2 3 4 5 6 7 SELECT livro1 FROM Livro livro1 WHERE NOT EXISTS ( SELECT livro2 FROM Livro livro2 WHERE livro1 . preco > livro2 . preco )
Cdigo Java 4.88: Seleciona os livros mais baratos
2. Suponha que seja necessrio selecionar os livros mais baratos de determinado autor.
www.k19.com.br
97
JPQL
1 2 3 4 5 6 7 8 9 1 SELECT livro1 FROM Livro livro1 , Autor autor WHERE autor1 . id = : id and livro1 MEMBER OF autor . livros and NOT EXISTS ( SELECT livro2 FROM Livro livro2 WHERE livro2 MEMBER OF autor . livros and livro1 . preco > livro2 . preco )
Cdigo Java 4.89: Seleciona os livros mais baratos de um determinado autor
98
3. Suponha que seja necessrio listar os livros em ordem decrescente em relao aos preos.
1 SELECT livro FROM Livro livro ORDER BY livro . preco DESC
Cdigo Java 4.90: Seleciona os livros em ordem decrescente de preo
Referncias
Para conhecer mais sobre a sintaxe do JPQL, consulte:
http://docs.oracle.com/cd/E28613_ 1/apirefs.1211/e24396/ejb3_langref.html
Consultas Nativas
Os provedores JPA tambm devem oferecer o suporte consultas nativas, ou seja, consultas denidas em SQL. Contudo, devemos lembrar que consultas denidas em SQL so especcas de um determinado banco de dados e eventualmente podem no funcionar em bancos de dados diferentes.
1 2 3 String sql = " SELECT * FROM Procuto " ; Query nativeQuery = manager . createNativeQuery ( sql , Produto . class ) ; List < Produto > produtos = nativeQuery . getResultList () ;
Cdigo Java 4.92: Selecionando os produtos com uma consulta nativa
Exerccios de Fixao
98
www.k19.com.br
99
JPQL
Testes as consultas nativas. Acrescente a seguinte classe no pacote br.com.k19.testes do projeto K19-JPQL.
26
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
public class TesteConsultaNativas { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_jpql_pu "); EntityManager manager = factory . createEntityManager () ; String sql = " SELECT * FROM Produto " ; Query nativeQuery = manager . createNativeQuery ( sql , Produto . class ) ; List < Produto > produtos = nativeQuery . getResultList () ; for ( Produto p : produtos ) { System . out . println ( p . getNome () ) ; } } }
Cdigo Java 4.93: TesteConsultaNativas.java
www.k19.com.br
99
JPQL
100
100
www.k19.com.br
CAPTULO
Cdigo Java 5.1: Obtendo um Criteria Builder a partir de um Entity Manager Cdigo Java 5.2: Iniciando a construo de uma consulta em Criteria
C RITERIA
O primeiro mecanismo denido pela especicao JPA 2 para realizar consultas orientadas a objetos utiliza a linguagem JPQL. O segundo mecanismo utiliza um conjunto de classes e interfaces e funciona basicamente como uma biblioteca. O nome dessa segunda abordagem Criteria.
Necessidade
A primeira questo a ser discutida nesse momento a necessidade de dois mecanismos para denio de consultas. Um mecanismo s no seria suciente? Teoricamente, qualquer consulta denida com JPQL pode ser denida com Criteria e vice-eversa. Contudo, algumas consultas so mais facilmente denidas em JPQL enquanto outras mais facilmente denidas em Criteria. As consultas que no dependem de informaes externas (por exemplo, buscar todos os livros cadastrados no banco de dados sem nenhum ltro) so mais facilmente denidas em JPQL. As consultas que dependem de informaes externas xas (por exemplo, buscar todos os livros cadastrados no banco de dados que possuam preo maior do que um valor denido pelos usurios) tambm so mais facilmente criadas em JPQL utilizando os parmetros de consulta. Agora, as consultas que dependem de informaes externas no xas so mais facilmente denidas em Criteria. Por exemplo, considere uma busca avanada por livros na qual h muitos campos opcionais. Essa consulta depende de informaes externas no xas j que nem todo campo far parte da consulta todas as vezes que ela for executada.
Estrutura Geral
As duas interfaces principais de Criteria so: CriteriaBuilder e CriteriaQuery. As consultas em Criteria so construdas por um Criteria Builder que obtido atravs de um Entity Manager.
1 CriteriaBuilder cb = manager . getCriteriaBuilder () ;
A denio de uma consulta em Criteria comea na chamada do mtodo createQuery() de um Criteria Builder. O parmetro desse mtodo indica o tipo esperado do resultado da consulta.
1 2 CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ;
www.k19.com.br
101
C RITERIA
102
Para denir quais dados devem ser considerados na consulta, devemos utilizar o mtodo from() da Criteria Query. Este mtodo devolve uma raiz do espao de dados considerado pela pesquisa.
1 2 3 4 CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ; // DEFININDO O ESPAO DE DADOS DA CONSULTA Root < Autor > a = c . from ( Autor . class ) ;
Cdigo Java 5.3: Denindo o espao de dadas da consulta
Para denir o que queremos selecionar do espao de dados da consulta, devemos utilizar o mtodo select() da Criteria Query.
1 2 3 4 5 6 CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ; // DEFININDO O ESPAO DE DADOS DA CONSULTA Root < Autor > a = c . from ( Autor . class ) ; // SELECIONANDO UMA RAIZ DO ESPAO DE DADOS c . select ( a ) ;
Cdigo Java 5.4: Denindo o que deve ser selecionado na consulta
Com a consulta em Criteria denida, devemos invocar um Entity Manager para poder execut-la da seguinte forma.
1 2 TypedQuery < Autor > query = manager . createQuery ( c ) ; List < Autor > autores = query . getResultList () ;
Cdigo Java 5.5: Executando a consulta
Exerccios de Fixao
Crie um projeto no eclipse chamado K19-Criteria. Copie a pasta lib do projeto K19-JPA2Hibernate para o projeto K19-Criteria. Depois adicione os jars dessa pasta no classpath desse novo projeto.
1 2 Abra o MySQL Workbench e apague a base de dados K21_criteria_bd se existir. Depois crie a base de dados K21_criteria_bd.
Copie a pasta META-INF do projeto K19-K19-JPA2-Hibernate para dentro da pasta src do projeto K19-Criteria. Altere o arquivo persistence.xml do projeto K19-Criteria, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
3
1 2 3 4 5 6 7 8 9 1 11 12 13 14
< persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_criteria_pu " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver "
102
www.k19.com.br
103
15 16 17 18 19 2 21 22 value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_criteria_bd " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML 5.1: persistence.xml
C RITERIA
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Autor { @Id @GeneratedValue private Long id ; private String nome ; @ManyToMany private Collection < Livro > livros = new ArrayList < Livro >() ; // GETTERS E SETTERS }
Cdigo Java 5.6: Autor.java
1 2 3 4 5 6 7 8 9 1 11 12
@Entity public class Livro { @Id @GeneratedValue private Long id ; private String nome ; private Double preco ; // GETTERS E SETTERS }
Cdigo Java 5.7: Livro.java
5 Carregue o banco de dados com as informaes de alguns livros e autores. Adicione a seguinte classe em um novo pacote chamado br.com.k19.testes no projeto K19-Criteria. Voc pode copiar a classe PopulaBanco criada no projeto K19-JPQL e alterar a unidade de persistncia.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16
public class PopulaBanco { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Livro livro1 = new Livro () ; livro1 . setNome ( " The Battle for Your Mind " ) ; livro1 . setPreco (2 .6) ; manager . persist ( livro1 ) ; Livro livro2 = new Livro () ; livro2 . setNome ( " Differentiate or Die " ) ; livro2 . setPreco (15.8) ;
www.k19.com.br
103
C RITERIA
17 18 19 2 21 22 23 24 25 26 27 28 29 3 31 32 33 34 35 36 37 38 39 4 41 42 43 44 45 46 47 48 49 5 51 52 53 54 55 56 57 58 59 6 61 62 63 64 65 66 67 68 69 manager . persist ( livro2 ) ; Livro livro3 = new Livro () ; livro3 . setNome ( " How to Transform Your Ideas " ) ; livro3 . setPreco (32.7) ; manager . persist ( livro3 ) ; Livro livro4 = new Livro () ; livro4 . setNome ( " Digital Fortress " ) ; livro4 . setPreco (12.9) ; manager . persist ( livro4 ) ; Livro livro5 = new Livro () ; livro5 . setNome ( " Marketing in an Era of Competition , Change and Crisis " ) ; livro5 . setPreco (26.8) ; manager . persist ( livro5 ) ; Autor autor1 = new Autor () ; autor1 . setNome ( " Patrick Cullen " ) ; autor1 . getLivros () . add ( livro2 ) ; autor1 . getLivros () . add ( livro4 ) ; manager . persist ( autor1 ) ; Autor autor2 = new Autor () ; autor2 . setNome ( " Fraser Seitel " ) ; autor2 . getLivros () . add ( livro3 ) ; manager . persist ( autor2 ) ; Autor autor3 = new Autor () ; autor3 . setNome ( " Al Ries " ) ; autor3 . getLivros () . add ( livro1 ) ; manager . persist ( autor3 ) ; Autor autor4 = new Autor () ; autor4 . setNome ( " Jack Trout " ) ; autor4 . getLivros () . add ( livro1 ) ; autor4 . getLivros () . add ( livro2 ) ; autor4 . getLivros () . add ( livro5 ) ; manager . persist ( autor4 ) ; Autor autor5 = new Autor () ; autor5 . setNome ( " Steve Rivkin " ) ; autor5 . getLivros () . add ( livro2 ) ; autor5 . getLivros () . add ( livro3 ) ; autor5 . getLivros () . add ( livro5 ) ; manager . persist ( autor5 ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java 5.8: PopulaBanco.java
104
6 Teste a os recursos de Criteria criando uma consulta para recuperar todos os livros cadastrados no banco de dados. Crie a seguinte classe no pacote br.com.k19.testes.
1 2 3 4 5 6 7 8 9
public class TesteCriteria { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > l = c . from ( Livro . class ) ;
104
www.k19.com.br
105
1 11 12 13 14 15 16 17 18 19 c . select ( l ) ; TypedQuery < Livro > query = manager . createQuery ( c ) ; List < Livro > livros = query . getResultList () ; for ( Livro livro : livros ) { System . out . println ( livro . getNome () ) ; } } }
Cdigo Java 5.9: TesteCriteria.java
C RITERIA
Exerccios Complementares
Crie uma consulta utilizando Criteria para recuperar todos os autores. Adicione uma classe para essa tarefa no pacote br.com.k19.testes do projeto K19-Criteria.
1
Tipos de Resultados
Lista de Entidades
O resultado de uma consulta em Criteria pode ser uma lista com os objetos de uma entidade que so compatveis com os ltros da pesquisa.
1 2 3 CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > livro = c . from ( Livro . class ) ; c . select ( livro ) ;
Cdigo Java 5.11: Uma consulta em Criteria
O resultado da consulta acima uma lista com todos os objetos da classe Livro.
A consulta acima recupera apenas os nomes dos livros. O resultado dessa pesquisa uma lista de strings.
www.k19.com.br
105
C RITERIA
106
Calcula a mdia de um conjunto de nmeros Contabiliza o nmero de resultados Recupera o maior elemento um conjunto de nmeros Recupera o menor elemento um conjunto de nmeros Calcula a soma de um conjunto de nmeros
Valores nicos
Algumas consultas possuem como resultado valores nicos. Por exemplo, suponha que queremos obter a mdia dos preos dos livros cadastrados no banco de dados ou a quantidade de livros de uma determinada editora. Nesse tipo de consulta, devemos apenas trazer do banco de dados um valor nico calculado no prprio banco.
1 2 3 CriteriaQuery < Double > c = cb . createQuery ( Double . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . select ( cb . avg ( l . < Double > get ( " preco " ) ) ) ;
Cdigo Java 5.13: Obtendo a mdia dos preos dos livros
A consulta acima devolve a mdia dos preos dos livros cadastrados no banco de dados. Nessa consulta, foi utilizada uma funo de agregao. Veja a lista dessas funes:
Resultados Especias
Podemos selecionar mltiplos atributos de uma entidade em uma consulta em Criteria. Por exemplo, podemos montar uma listagem com os nomes e preos dos livros cadastrados no banco de dados. Para selecionar mltiplos atributos, devemos utilizar o mtodo multiselect().
1 2 3 CriteriaQuery < Object [] > c = cb . createQuery ( Object []. class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . multiselect ( l . < String > get ( " nome " ) , l . < Double > get ( " preco " ) ) ;
Cdigo Java 5.14: Selecionando os nomes e os preos dos livros
O resultado da consulta acima uma lista de array de Object. Para manipular esse resultado, temos que utilizar a posio dos dados dos arrays da lista.
1 2 3 4 5 6 7 TypedQuery < Object [] > query = manager . createQuery ( c ) ; List < Object [] > resultado = query . getResultList () ; for ( Object [] registro : resultado ) { System . out . println ( " Livro : " + registro [ ]) ; System . out . println ( " Preo : " + registro [1]) ; }
Cdigo Java 5.15: Manipulando os resultados da consulta
Tambm podemos utilizar a interface Tuple para no trabalhar com posicionamento de dados em arrays. Nessa abordagem, devemos aplicar apelidos para os itens selecionados atravs do mtodo alias().
106
www.k19.com.br
107
1 2 3 4 5 6 7 8 9 1 11
C RITERIA
CriteriaQuery < Tuple > c = cb . createQuery ( Tuple . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . multiselect ( l . < String > get ( " nome " ) . alias ( " livro . nome " ) , l . < Double > get ( " preco " ) . alias ( " livro . preco " ) ) ; TypedQuery < Tuple > query = manager . createQuery ( c ) ; List < Tuple > resultado = query . getResultList () ; for ( Tuple registro : resultado ) { System . out . println ( " Livro : " + registro . get ( " livro . nome " ) ) ; System . out . println ( " Preo : " + registro . get ( " livro . preco " ) ) ; }
Cdigo Java 5.16: Usando a interface Tuple para manipular os dados da consulta
Exerccios de Fixao
Recupere uma listagem com os nomes dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-Criteria.
7
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22
public class ListaNomesDosLivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < String > c = cb . createQuery ( String . class ) ; Root < Livro > livro = c . from ( Livro . class ) ; c . select ( livro . < String > get ( " nome " ) ) ; TypedQuery < String > query = manager . createQuery ( c ) ; List < String > nomes = query . getResultList () ; for ( String nome : nomes ) { System . out . println ( " Livro : " + nome ) ; } manager . close () ; factory . close () ; } }
Cdigo Java 5.17: ListaNomesDosLivros.java
Recupere a mdia dos valores dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-Criteria.
8
1 2 3 4 5 6 7 8 9 1 11 12 13 14
public class CalculaMediaDosPrecosDosLivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Double > c = cb . createQuery ( Double . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . select ( cb . avg ( l . < Double > get ( " preco " ) ) ) ; TypedQuery < Double > query = manager . createQuery ( c ) ; Double media = query . getSingleResult () ;
www.k19.com.br
107
C RITERIA
15 16 17 18 19 2 System . out . println ( " Mdia : " + media ) ; manager . close () ; factory . close () ; } }
Cdigo Java 5.18: CalculaMediaDosPrecosDosLivros.java
108
Recupere os nomes e os preos dos livros cadastrados no banco de dados. Adicione a seguinte classe no pacote br.com.k19.testes do projeto K19-Criteria.
9
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23
public class ConsultaNomePrecoDosLivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Object [] > c = cb . createQuery ( Object []. class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . multiselect ( l . < String > get ( " nome " ) , l . < Double > get ( " preco " ) ) ; TypedQuery < Object [] > query = manager . createQuery ( c ) ; List < Object [] > resultado = query . getResultList () ; for ( Object [] registro : resultado ) { System . out . println ( " Livro : " + registro [ ]) ; System . out . println ( " Preo : " + registro [1]) ; } manager . close () ; factory . close () ; } }
Cdigo Java 5.19: ConsultaNomePrecoDosLivros.java
10
Altere a classe do exerccio anterior para que ela utilize a interface Tuple.
public class ConsultaNomePrecoDosLivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Tuple > c = cb . createQuery ( Tuple . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . multiselect ( l . < String > get ( " nome " ) . alias ( " livro . nome " ) , l . < Double > get ( " preco " ) . alias ( " livro . preco " ) ) ; TypedQuery < Tuple > query = manager . createQuery ( c ) ; List < Tuple > resultado = query . getResultList () ; for ( Tuple registro : resultado ) { System . out . println ( " Livro : " + registro . get ( " livro . nome " ) ) ; System . out . println ( " Preo : " + registro . get ( " livro . preco " ) ) ; } manager . close () ; factory . close () ; } }
Cdigo Java 5.20: ConsultaNomePrecoDosLivros.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23
108
www.k19.com.br
109
C RITERIA
Filtros e Predicados
Podemos denir ltros para as consultas atravs da criao de Predicates e do mtodo where() de uma Criteria Query. Os predicados so condies que devem ser satisfeitas para que uma informao seja adicionada no resultado de uma consulta. Eles so criados por um Criteria Builder.
1 2 3 4 5 6 7 8 9 CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ; Root < Autor > a = c . from ( Autor . class ) ; c . select ( a ) ; // CRIANDO UM PREDICATE Predicate predicate = cb . equal ( a . get ( " nome " ) , " Patrick Cullen " ) ; // ASSOCIANDO O PREDICATE A CONSULTA c . where ( predicate ) ;
Cdigo Java 5.21: Criando um predicado e associando-o a uma consulta
Exerccios de Fixao
11 Teste uma consulta com Criteria criando uma classe para recuperar todos os livros cadastrados no banco de dados ltrando os pelo nome. Crie a seguinte classe no pacote br.com.k19.testes do projeto K19-Criteria.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24
public class TestePredicate { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . select ( l ) ; Predicate predicate = cb . equal ( l . get ( " nome " ) , " The Battle for Your Mind " ) ; c . where ( predicate ) ; TypedQuery < Livro > query = manager . createQuery ( c ) ; List < Livro > livros = query . getResultList () ; for ( Livro livro : livros ) { System . out . println ( livro . getId () ) ; System . out . println ( livro . getNome () ) ; System . out . println ( livro . getPreco () ) ; } } }
Cdigo Java 5.22: TestePredicate.java
Lista de Predicados
equal()
www.k19.com.br
109
C RITERIA
1 cb . equal ( livro . get ( " nome " ) , " The Battle for Your Mind " ) ;
Cdigo Java 5.23: Vericando se o nome do livro igual a The Battle for Your Mind
110
and()
1 cb . and ( cb . equal ( livro . get ( " nome " ) , " Noites " ) , cb . equal ( livro . get ( " editora " ) , " Saraiva " ) ) ;
Cdigo Java 5.24: Vericando se o livro tem o nome Noites e sua editora Saraiva.
or()
1 cb . or ( cb . equal ( livro . get ( " nome " ) , " Noites " ) , cb . equal ( livro . get ( " editora " ) , " Saraiva " ) ) ;
Cdigo Java 5.25: Vericando se o livro possui o nome Noites ou se sua editora Saraiva.
notEqual()
1 cb . notEqual ( livro . get ( " nome " ) , " The Battle for Your Mind " ) ;
Cdigo Java 5.26: Vericando se o nome do livro diferente de The Battle for Your Mind
not()
1 cb . not ( cb . equal ( livro . get ( " nome " ) , " The Battle for Your Mind " ) ) ;
Cdigo Java 5.27: Vericando se o nome do livro diferente de The Battle for Your Mind
greaterThan(), gt()
1 cb . gt ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.28: Vericando se o preo do livro maior do que 20.0
ou
1 cb . greaterThan ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.29: Vericando se o preo do livro maior do que 20.0
greaterThanOrEqualTo(), ge()
1 cb . ge ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.30: Vericando se o preo do livro maior do que ou igual a 20.0
ou
1 cb . greaterThanOrEqualTo ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.31: Vericando se o preo do livro maior do que ou igual a 20.0
lessThan(), lt()
1 cb . lt ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.32: Vericando se o preo do livro menor do que 20.0
110
www.k19.com.br
111
C RITERIA
ou
1 cb . lessThan ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.33: Vericando se o preo do livro menor do que 20.0
lessThanOrEqualTo(), le()
1 cb . le ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.34: Vericando se o preo do livro menor do que ou igual a 20.0
ou
1 cb . lessThanOrEqualTo ( livro . < Double > get ( " preco " ) , 2 . ) ;
Cdigo Java 5.35: Vericando se o preo do livro menor do que ou igual a 20.0
between()
1 cb . between ( livro . < Double > get ( " preco " ) , 2 . , 3 . ) ;
Cdigo Java 5.36: Vericando se o preo do livro est entre 20.0 e 30.0 inclusive
isNull()
1 cb . isNull ( livro . get ( " nome " ) ) ;
Cdigo Java 5.37: Vericando se o nome dos livros so nulos
isNotNull()
1 cb . isNotNull ( livro . get ( " nome " ) ) ;
Cdigo Java 5.38: Vericando se o nome dos livros no so nulos
isEmpty()
1 cb . isEmpty ( autor . < Collection < Livro > > get ( " livros " ) ) ;
Cdigo Java 5.39: Vericando se a lista de livros dos autores est vazia
isNotEmpty()
1 cb . isNotEmpty ( autor . < Collection < Livro > > get ( " livros " ) ) ;
Cdigo Java 5.40: Vericando se a lista de livros dos autores no est vazia
isMember()
1 cb . isMember ( livro , livro . < Editora > get ( " editora " ) . < Collection < Livro > > get ( " maisVendidos " ) ) ;
Cdigo Java 5.41: Vericando se os livros esto na coleo dos livros mais vendidos de suas respectivas editoras
isNotMember()
www.k19.com.br
111
C RITERIA
1
112
cb . isNotMember ( livro , livro . < Editora > get ( " editora " ) . < Collection < Livro > > get ( " maisVendidos " ) ) ;
Cdigo Java 5.42: Vericando se os livros no esto na coleo dos livros mais vendidos de suas respectivas editoras
like()
1 cb . like ( livro . < String > get ( " nome " ) , " % Battle % " ) ;
Cdigo Java 5.43: Determinando se o nome dos livros seguem o padro especicado
notLike()
1 cb . notLike ( livro . < String > get ( " nome " ) , " % Battle % " ) ;
Cdigo Java 5.44: Determinando se o nome dos livros no seguem o padro especicado
in()
1 cb . in ( livro . < String > get ( " editora " ) ) . value ( " Saraiva " ) . value ( " Moderna " ) ;
Cdigo Java 5.45: Vericando se a editora dos livros igual a uma das editoras especicadas
ou
1 livro . < String > get ( " editora " ) . in ( " Saraiva " ," Moderna " ) ;
Cdigo Java 5.46: Vericando se a editora dos livros igual a uma das editoras especicadas
Funes
abs()
1 cb . abs ( livro . < Double > get ( " preco " ) ) ;
Cdigo Java 5.47: Obtendo o valor absoluto do preo dos produtos
concat()
1 cb . concat ( livro1 . < String > get ( " nome " ) , livro2 . < String > get ( " nome " ) ) ;
Cdigo Java 5.48: Concatenando o nome de dois livros
currentDate()
1 cb . currentDate () ;
Cdigo Java 5.49: Recuperando a data atual
currentTime()
112
www.k19.com.br
113
1 cb . currentTime () ;
Cdigo Java 5.50: Recuperando o horrio atual
C RITERIA
currentTimestamp()
1 cb . currentTimestamp () ;
Cdigo Java 5.51: Recuperando a data e o horrio atual
length()
1 cb . length ( livro . < String > get ( " nome " ) ) ;
Cdigo Java 5.52: Obtendo a quantidade de caracteres dos nomes dos livros
locate()
1 cb . locate ( livro1 . < String > get ( " nome " ) , livro2 . < String > get ( " nome " ) ) ;
Cdigo Java 5.53: Vericando a posio do nome de um autor dentro do nome de outro autor
lower()
1 cb . lower ( livro . < String > get ( " nome " ) ) ;
Cdigo Java 5.54: Colocando o nome dos livros em caixa baixa
mod()
1 cb . mod ( autor1 . < Integer > get ( " idade " ) , autor2 . < Integer > get ( " idade " ) ) ;
Cdigo Java 5.55: Calculando o resto da diviso entre as idades de dois autores
size()
1 cb . size ( autor . < Collection < Livro > > get ( " livros " ) ) ;
Cdigo Java 5.56: Recuperando a quantidade de livros dos autores
sqrt()
1 cb . sqrt ( autor . < Integer > get ( " idade " ) ) ;
Cdigo Java 5.57: Calculando a raiz quadrada das idades dos autores
substring()
1 cb . substring ( livro . < String > get ( " nome " ) , 3 , 5) ;
Cdigo Java 5.58: Obtendo um determinado trecho dos nomes dos livros
upper()
www.k19.com.br
113
C RITERIA
1 cb . upper ( livro . < String > get ( " nome " ) ) ;
Cdigo Java 5.59: Colocando os nomes do livros em caixa alta
114
trim()
1 cb . trim ( livro . < String > get ( " nome " ) ) ;
Cdigo Java 5.60: Removendo eventuais espaos do incio e do nal do nome dos livros
Ordenao
Os resultados das consultas em Criteria tambm podem ser ordenados. Para isso, basta utilizarmos o mtodo orderBy()
1 2 3 4 5 CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > livro = c . from ( Livro . class ) ; c . select ( livro ) ; c . orderBy ( cb . desc ( livro . < Double > get ( " preco " ) ) ) ;
Cdigo Java 5.61: Ordenando o resultado de uma consulta em Criteria
Subqueries
Algumas consultas necessitam de consultas auxiliares. Por exemplo, para encontrar o livro mais caro cadastrado no banco de dados, devemos criar uma consulta auxiliar para poder comparar, dois a dois, os preos dos livros. Uma consulta auxiliar ou uma subquery criada atravs do mtodo subquery(). No exemplo abaixo, criamos uma consulta e uma sub-consulta para encontrar o livro mais caro.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > livro1 = c . from ( Livro . class ) ; c . select ( livro1 ) ; Subquery < Livro > subquery = c . subquery ( Livro . class ) ; Root < Livro > livro2 = subquery . from ( Livro . class ) ; subquery . select ( a2 ) ; Predicate predicate = cb . greaterThan ( livro2 . < Double > get ( " preco " ) , livro1 . < Double > get ( " preco " ) ) ; subquery . where ( predicate ) ; Predicate predicate2 = cb . not ( cb . exists ( subquery ) ) ; c . where ( predicate2 ) ;
Cdigo Java 5.62: Consulta e sub-consulta para encontrar o livro mais caro
Exemplos
114
www.k19.com.br
115
C RITERIA
1. Suponha que seja necessrio selecionar os livros mais baratos. Em outras palavras, devemos selecionar os livros tais que no exista nenhum outro livro com preo menor.
1 2 3 4 5 6 7 8 9 1 11 12 CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > livro1 = c . from ( Livro . class ) ; c . select ( livro1 ) ; Subquery < Livro > subquery = c . subquery ( Livro . class ) ; Root < Livro > livro2 = subquery . from ( Livro . class ) ; subquery . select ( livro2 ) ; Predicate gt = cb . gt ( livro1 . < Double > get ( " preco " ) , livro2 . < Double > get ( " preco " ) ) ; subquery . where ( gt ) ; Predicate notExists = cb . not ( cb . exists ( subquery ) ) ; c . where ( notExists ) ;
Cdigo Java 5.63: Selecionando os livros mais baratos
2. Suponha que seja necessrio selecionar os livros mais baratos de um determinado autor.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > livro1 = c . from ( Livro . class ) ; Root < Autor > autor1 = c . from ( Autor . class ) ; c . select ( livro1 ) ; Subquery < Livro > subquery = c . subquery ( Livro . class ) ; Root < Livro > livro2 = subquery . from ( Livro . class ) ; Root < Autor > autor2 = subquery . from ( Autor . class ) ; subquery . select ( livro2 ) ; Predicate isMember1 = cb . isMember ( livro2 , autor2 . < Collection < Livro > > get ( " livros " ) ) ; Predicate equal1 = cb . equal ( autor2 , autor1 ) ; Predicate gt = cb . gt ( livro1 . < Double > get ( " preco " ) , livro2 . < Double > get ( " preco " ) ) ; Predicate predicate = cb . and ( isMember1 , equal1 , gt ) ; subquery . where ( predicate ) ; Predicate notExists = cb . not ( cb . exists ( subquery ) ) ; Predicate equal2 = cb . equal ( autor1 . < String > get ( " nome " ) , " Jack Trout " ) ; Predicate isMember2 = cb . isMember ( livro1 , autor1 . < Collection < Livro > > get ( " livros " ) ) ; Predicate predicate2 = cb . and ( isMember2 , equal2 , notExists ) ; c . where ( predicate2 ) ;
Cdigo Java 5.64: Selecionando os livros mais barato do autor Jack Trout
3. Suponha que seja necessrio listar os livros em ordem decrescente em relao aos preos.
1 2 3 4 CriteriaQuery < Livro > c = cb . createQuery ( Livro . class ) ; Root < Livro > livro = c . from ( Livro . class ) ; c . select ( livro ) ; c . orderBy ( cb . desc ( livro . < Double > get ( " preco " ) ) ) ;
Cdigo Java 5.65: Ordenando o resultado da consulta por ordem decrescente de preo
www.k19.com.br
115
C RITERIA
11 12 Predicate notExists = cb . not ( cb . exists ( subquery ) ) ; c . where ( notExists ) ;
Cdigo Java 5.66: Selecionando os autores com mais livros
116
O Problema do N + 1
No Captulo 4, vimos que o uso do modo LAZY em relacionamentos pode provocar um nmero excessivo de consultas ao banco de dados em alguns casos. Assim como em JPQL, tambm podemos evitar esse problema usando fetch join em Criteria. Por exemplo, considere as entidades Departamento e Funcionario.
1 2 3 4 5 6 7 8 9 1 @Entity public class Funcionario { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java 5.67: Funcionario.java
1 2 3 4 5 6 7 8 9 1 11 12 13
@Entity public class Departamento { @Id @GeneratedValue private Long id ; private String nome ; @OneToMany private List < Funcionario > funcionarios ; // GETTERS E SETTERS }
Cdigo Java 5.68: Departamento.java
Se optarmos pelo modo LAZY no relacionamento entre departamentos e funcionrios, ento uma consulta para selecionar os departamentos no trar de imediato os seus respectivos funcionrios. Para que os funcionrios sejam recuperados na mesma consulta em que os departamentos so selecionados, podemos usar o mtodo fetch(). Veja o exemplo abaixo.
1 2 3 4 5 CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Departamento > c = cb . createQuery ( Departamento . class ) ; Root < Departamento > d = c . from ( Departamento . class ) ; d . fetch ( " funcionarios " , JoinType . LEFT ) ; c . select ( d ) . distinct ( true ) ;
Cdigo Java 5.69: Consulta para obter os departamentos e seus respectivos funcionrios
Nesse exemplo, o mtodo distinct() usado para garantir que no haja elementos repetidos na lista obtida pela consulta.
116
www.k19.com.br
117
C RITERIA
Exerccios de Fixao
Faa uma consulta para obter todos os autores e seus respectivos livros. No pacote br.com.k19.testes do projeto K19-Criteria, crie a classe ListaAutoresELivros.
12
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28 29 3
public class ListaAutoresELivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ; Root < Autor > a = c . from ( Autor . class ) ; c . select ( a ) ; TypedQuery < Autor > query = manager . createQuery ( c ) ; List < Autor > autores = query . getResultList () ; System . out . println () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; Collection < Livro > livros = autor . getLivros () ; for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; } System . out . println () ; } manager . close () ; factory . close () ; } }
Cdigo Java 5.70: ListaAutoresELivros.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class ListaAutoresELivros { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ; Root < Autor > a = c . from ( Autor . class ) ; a . fetch ( " livros " , JoinType . LEFT ) ; c . select ( a ) . distinct ( true ) ; TypedQuery < Autor > query = manager . createQuery ( c ) ; List < Autor > autores = query . getResultList () ; System . out . println () ; for ( Autor autor : autores ) { System . out . println ( " Autor : " + autor . getNome () ) ; Collection < Livro > livros = autor . getLivros () ;
www.k19.com.br
117
C RITERIA
21 22 23 24 25 26 27 28 29 3 31
118
for ( Livro livro : livros ) { System . out . println ( " Livro : " + livro . getNome () ) ; } System . out . println () ; } manager . close () ; factory . close () ; } }
Cdigo Java 5.71: ListaAutoresELivros.java
Metamodel
Quando denimos uma consulta em Criteria, estamos propensos a confundir os nomes ou os tipos dos atributos das entidades, j que o compilador no realiza a vericao dessas informaes. Dessa forma, os erros s seriam percebidos em tempo de execuo. Considere o exemplo abaixo.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 public class CalculaMedia { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Float > c = cb . createQuery ( Float . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . select ( cb . max ( l . < Float > get ( " preo " ) ) ) ; TypedQuery < Float > query = manager . createQuery ( c ) ; Float maiorPreco = query . getSingleResult () ; System . out . println ( " Maior preo : " + maiorPreco ) ; manager . close () ; factory . close () ; } }
Cdigo Java 5.72: CalculaMedia.java
Nesse cdigo, cometemos dois erros. O primeiro deles foi supor que o atributo que armazena o preo dos livros do tipo Float. Na verdade, esse atributo do tipo Double. O segundo erro foi um simples erro de digitao, pois utilizamos a string "preo" ao invs de "preco". Esses erros no so identicados pelo compilador, mas durante a execuo uma exceo ser lanada. Para evitar que o desenvolvedor cometa erros desse tipo, podemos aplicar o recurso conhecido como Metamodel, denido pela especicao JPA 2. Note que os erros cometidos no exemplo acima esto relacionados ao tipo e ao nome do atributo
preco da entidade Livro. A funo do Metamodel justamente armazenar as informaes referentes aos nomes e tipos dos atributos das entidades. Por exemplo, para a entidade Livro, teramos uma
classe semelhante classe do cdigo abaixo.
118
www.k19.com.br
119
1 2 3 4 5 6 7 @Generated ( value = " org . hibernate . jpamodelgen . JPAMetaModelEntityProcessor " ) @StaticMetamodel ( Livro . class ) public abstract class Livro_ { public static volatile SingularAttribute < Livro , Long > id ; public static volatile SingularAttribute < Livro , Double > preco ; public static volatile SingularAttribute < Livro , String > nome ; }
C RITERIA
A classe Livro_ foi gerada automaticamente pelo Hibernate a partir da classe Livro. Ela segue as regras do Canonical Metamodel denidas pela especicao JPA 2. O prximo passo utilizar o Canonical Metamodel da entidade Livro para denir a consulta anterior. Veja o cdigo abaixo.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 public class CalculaMedia { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_entity_manager " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Double > c = cb . createQuery ( Double . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . select ( cb . max ( l . get ( Livro_ . preco ) ) ) ; TypedQuery < Double > query = manager . createQuery ( c ) ; Double maiorPreco = query . getSingleResult () ; System . out . println ( " Maior preo : " + maiorPreco ) ; manager . close () ; factory . close () ; } }
Uma vez que utilizamos o Canonical Metamodel (Livro_) da entidade Livro, no possvel parametrizar a consulta com outro tipo a no ser o Double, pois um erro de compilao ocorrer. Alm disso, tambm no podemos mais cometer o erro relacionado ao nome do atributo da entidade, sem que haja uma falha na compilao.
Exerccios de Fixao
14 Copie a pasta Hibernate-Metamodel-Generator localizada na rea de Trabalho dentro do diretrio K19-Arquivos para a pasta raiz do projeto K19-Criteria. Em seguida, clique com o boto direito do mouse sobre o projeto K19-Criteria, selecione a opo Properties e congure o Hibernate Metamodel Generator de acordo com as guras abaixo.
www.k19.com.br
119
C RITERIA
120
120
www.k19.com.br
121
C RITERIA
15 Abra o diretrio target/metamodel e verique se as classes que formam o Canonical Metamodel foram geradas.
No pacote br.com.k19.testes do projeto K19-Criteria, crie uma classe chamada ConsultaLivroMaisCaro. Usando os recursos do Metamodel, faa uma consulta base de dados K21_criteria_bd para saber o preo do livro mais caro.
16
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class ConsultaLivroMaisCaro { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Double > c = cb . createQuery ( Double . class ) ; Root < Livro > l = c . from ( Livro . class ) ; c . select ( cb . max ( l . get ( Livro_ . preco ) ) ) ; TypedQuery < Double > query = manager . createQuery ( c ) ; Double maiorPreco = query . getSingleResult () ; System . out . println ( " Maior preo : " + maiorPreco ) ; manager . close () ; factory . close () ; } }
Cdigo Java 5.75: ConsultaLivroMaisCaro.java
www.k19.com.br
121
C RITERIA
122
122
www.k19.com.br
APNDICE
H IBERNATE S EARCH
Eventualmente, uma aplicao Java necessita realizar constantemente buscas em uma grande quantidade de textos. Existem bibliotecas Java especializadas nesse tipo de tarefa. A mais utilizada delas Apache Lucene (http://lucene.apache.org) da Apache Software Foundation. A integrao entre os recursos oferecidos pelo Lucene e uma aplicao orientada a objetos complexa. O projeto Hibernate Search (http://www.hibernate.org/subprojects/search) tem como principal objetivo facilitar essa integrao. O Hibernate Search um subprojeto do Hibernate. Neste captulo, mostraremos o funcionamento bsico do Hibernate Search.
Congurao
Para utilizar os recursos do Hibernate Search em uma aplicao Java, devemos adicionar as bibliotecas do Hibernate Search e das suas dependncias. Podemos obter essas bibliotecas em http: //www.hibernate.org/subprojects/search/download. Neste curso, utilizaremos a verso 4.1.1 do Hibernate Search. Aps adicionar as bibliotecas necessrias, devemos acrescentar ao arquivo persistence.xml de uma aplicao JPA algumas propriedades para que o Hibernate Search possa ser utilizado. Veja as modicaes em destaque no cdigo abaixo.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 < persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K19 - PU " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < shared - cache - mode > ALL </ shared - cache - mode > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / k19_bd " / > < property name = " hibernate . search . default . directory_provider " value = " filesystem " / > < property name = " hibernate . search . default . indexBase " value = " / k19 / indexes " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML A.1: persistence.xml
www.k19.com.br
123
H IBERNATE S EARCH
124
No cdigo acima, a propriedade hibernate.search.default.directory_provider dene o DirectoryProvider. Alm disso, a propriedade hibernate.search.default.indexBase dene o diretrio os ndices do Lucene sero gerados. Mais sobre a congurao do DirectoryProvider pode ser encontrada em http://www.hibernate.org/subprojects/search/docs.
Mapeamento
Podemos realizar buscas apenas nos dados das entidades indexadas. Para indicar quais entidades devem ser indexadas pelo Lucene, devemos utilizar a anotao @Indexed do Hibernate Search. Alm disso, apenas o contedo dos atributos anotados com @Field ser considerado nas buscas do Lucene.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 @Entity @Indexed public class Pessoa { @Id @GeneratedValue private Long id ; @Field private String nome ; @Lob @Field private String biografia ; }
Cdigo Java A.1: Pessoa.java
Indexao
A partir do momento que as entidades esto mapeadas com as anotaes do Hibernate Search, podemos indexar os dados armazenados no banco de dados referentes s entidades anotadas com @Indexed. Para realizar essa tarefa, devemos invocar o mtodo createIndexer() da interface FullTextEntityManager. Veja o cdigo abaixo.
1 2 3 EntityManager manager = . . . FullTextEntityManager fullTextManager = Search . getFullTextEntityManager ( manager ) ; fullTextManager . createIndexer () . startAndWait () ;
Cdigo Java A.2: Indexando o contedo do banco de dados
Busca
Com o contedo indexado, podemos realizar buscas atravs do Hibernate Search. Para isso, devemos recuperar a fbrica de buscas por meio do mtodo getSearchFactory() da FullTextEntityManager. Com a fbrica em mos, devemos criar um montador de consultas para uma entidade em particular. Observe o cdigo a seguir.
1 2 SearchFactory searchFactory = fullTextManager . getSearchFactory () ; QueryBuilder pessoaQueryBuilder =
124
www.k19.com.br
125
3 searchFactory . buildQueryBuilder () . forEntity ( Pessoa . class ) . get () ;
Cdigo Java A.3: Obtendo um montador de consultas para a entidade Pessoa
H IBERNATE S EARCH
Agora, atravs do QueryBuilder, podemos criar as consultas desejadas. Por exemplo, suponha que desejemos buscar as pessoas que possuam a palavra programador em sua biograa. Ento, devemos indicar que a busca ser realizada por palavra chave atravs do mtodo keyword(). Alm disso, devemos indicar qual atributo da entidade Pessoa ser considerado na busca com o mtodo onField(). A palavra procurada deve ser denida atravs do mtodo matching(). Veja o cdigo abaixo.
1 2 org . apache . lucene . search . Query luceneQuery = pessoaQueryBuilder . keyword () . onField ( " biografia " ) . matching ( " programador " ) ;
Cdigo Java A.4: Criando uma consulta
O prximo passo transformar essa consulta do Lucene em uma consulta JPA. Essa tarefa realizada com o mtodo createFullTextQuery().
1 2 javax . persistence . Query jpaQuery = fullTextManager . createFullTextQuery ( luceneQuery , Pessoa . class ) ;
Cdigo Java A.5: Transformando uma Lucene Query em uma JPA Query
Exerccios de Fixao
Crie um projeto no eclipse chamado K19-Hibernate-Search. Nesse projeto, adicione uma pasta chamada lib.
1 2 Entre na pasta K19-Arquivos/hibernate-search-4.1.1.Final/dist da rea de Trabalho e copie os jars dessa pasta, os da pasta lib/required, os da pasta lib/provided e os da pasta lib/optional para a pasta lib do projeto K19-Hibernate-Search. 3
Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-Hibernate-Search. Altere o arquivo persistence.xml do projeto K19-Hibernate-Search, mo5
dicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 < persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance "
www.k19.com.br
125
H IBERNATE S EARCH
4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_hibernate_search " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_hibernate_search " / > < property name = " hibernate . search . default . directory_provider " value = " filesystem " / > < property name = " hibernate . search . default . indexBase " value = " / tmp / indexes " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML A.2: persistence.xml
126
1 2 3 4 5 6 7 8 9 1 11 12
@Entity @Indexed public class Pessoa { @Id @GeneratedValue private Long id ; @Field private String nome ; // GETTERS E SETTERS }
Cdigo Java A.7: Pessoa.java
Persista alguns objeto da classe Pessoa. Crie uma classe chamada AdicionaPessoa dentro de um pacote chamado testes.
7
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19
public class AdicionaPessoa { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_hibernate_search " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Pessoa p1 = new Pessoa () ; p1 . setNome ( " Rafael Cosentino " ) ; Pessoa p2 = new Pessoa () ; p2 . setNome ( " Jonas Hirata " ) ; Pessoa p3 = new Pessoa () ; p3 . setNome ( " Marcelo Martins " ) ; Pessoa p4 = new Pessoa () ; p4 . setNome ( " Christopher Hirata " ) ;
126
www.k19.com.br
127
2 21 22 23 24 25 26 27 28 29 3
H IBERNATE S EARCH
manager . persist ( p1 ) ; manager . persist ( p2 ) ; manager . persist ( p3 ) ; manager . persist ( p4 ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java A.8: AdicionaPessoa.java
Execute a indexao dos dados armazenados no banco de dados. Crie uma classe chamada
Busque as pessoas que possuam a palavra Hirata em seus nomes. Crie uma classe chamada
www.k19.com.br
127
H IBERNATE S EARCH
128
128
www.k19.com.br
APNDICE
H IBERNATE E NVERS
Eventualmente, necessrio registrar todas as alteraes realizadas nos registros correspondentes s instncias de determinadas entidades de uma aplicao JPA. Por exemplo, considere um sistema bancrio que necessita registrar todas as modicaes nos saldos das contas para uma eventual auditoria. Manter o histrico das alteraes dos registros do banco de dados pode ser til por diversos motivos. Por exemplo, recuperar dados que no deveriam ter sido modicados ou identicar uso indevido da aplicao por parte dos usurios. O projeto Hibernate ORM possui recursos especcos para esse tipo de problema. Mais especicamente, o Hibernate Envers que faz parte do Hibernate ORM oferece mecanismos para controlar as modicaes realizadas nos dados do banco de dados. Neste captulo, mostraremos como utilizar as principais funcionalidades do Hibernate Envers. Utilizaremos a verso 4.1.2 do Hibernate ORM que j possui o Hibernate Envers. As bibliotecas necessrias podem ser obtidas em http://www.hibernate.org/downloads.
Mapeamento
As entidades que devem ser monitoradas pelo Hibernate Envers devem ser anotadas com @Audited.
1 2 3 4 5 6 7 8 9 1 11 @Entity @Audited public Pessoa { @Id @GeneratedValue private Long id ; private String nome ; }
Cdigo Java B.1: Pessoa.java
Para cada entidade anotada com @Audited, uma tabela extra ser criada no banco de dados para armazenar o histrico das modicaes nas instncias da entidade. Por padro, o nome dessa tabela a concatenao do nome da entidade com o suxo _AUD. Por exemplo, ao anotar a entidade Pessoa com @Audited, uma tabela chamada Pessoa_AUD criada no banco de dados para armazenar as alteraes na tabela Pessoa. Todo registro da tabela Pessoa_AUD corresponde a um nico registro da tabela Pessoa. Os registros da tabela Pessoa_AUD possuem basicamente os mesmos campos dos registros da tabela Pessoa. Toda vez que um registro inserido, modicado ou removido da tabela Pessoa um registro com
www.k19.com.br
129
H IBERNATE E NVERS
130
basicamente os mesmos dados inserido na tabela Pessoa_AUD. Os registros inseridos na tabela Pessoa_AUD possuem tambm um campo chamado REV e outro chamado REVTYPE. O campo REV armazena a verso do registro correspondente na tabela Pessoa. O campo REVTYPE indica se o registro da tabela Pessoa_AUD foi gerado a partir de uma insero, modicao ou remoo na tabela Pessoa. Nas inseres o campo REVTYPE armazenar o valor 0, nas modicaes armazenar o valor 1 e nas remoes o valor 2.
Consultas
O Hibernate Envers permite que os dados das instncias de uma entidade sejam recuperados de acordo com verso do registro. Por exemplo, podemos recuperar a primeira verso de um determinado registro.
1 2 3 4 5 6 7 EntityManager manager = . . . AuditReader reader = AuditReaderFactory . get ( manager ) ; AuditQuery query = reader . createQuery () . forEntitiesAtRevision ( Pessoa . class , 1) ; query . add ( AuditEntity . property ( " id " ) . eq (1 L ) ) ; Pessoa p = ( Pessoa ) query . getSingleResult () ;
Cdigo Java B.2: Recuperando a primeira verso de um determinado registro
Exerccios de Fixao
Crie um projeto no eclipse chamado K19-Hibernate-Envers. Copie a pasta lib do projeto K19JPA2-Hibernate para o projeto K19-Hibernate-Envers.
1
Entre na pasta K19-Arquivos/hibernate-release-4.1.2.Final/lib da rea de Trabalho e copie o jar da pasta envers para a pasta lib do projeto K19-Hibernate-Envers.
2
Depois selecione todos os jars da pasta lib do projeto K19-Hibernate-Envers e adicione-os no classpath.
3
Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-Hibernate-Envers. Altere o arquivo persistence.xml do projeto K19-Hibernate-Envers, mo4
dicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 1 11 12 13 < persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_hibernate_envers " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver "
130
www.k19.com.br
131
14 15 16 17 18 19 2 21 value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_hibernate_envers " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML B.1: persistence.xml
H IBERNATE E NVERS
1 2 3 4 5 6 7 8 9 1 11
@Entity @Audited public class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java B.3: Pessoa.java
Persista um objeto da classe Pessoa. Crie uma classe chamada AdicionaPessoa dentro de um pacote chamado testes.
6
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
public class AdicionaPessoa { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_hibernate_envers " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Pessoa p = new Pessoa () ; p . setNome ( " Rafael Cosentino " ) ; manager . persist ( p ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java B.4: AdicionaPessoa.java
Execute e consulte o banco de dados atravs do MySQL Workbench! Altere o objeto da classe Pessoa persistido anteriormente. Crie uma classe chamada AlteraPessoa dentro de um pacote chamado testes.
7
1 2 3 4 5 6 7
public class AlteraPessoa { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_hibernate_envers " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ;
www.k19.com.br
131
H IBERNATE E NVERS
8 9 1 11 12 13 14 15 16 17
132
Pessoa p = manager . find ( Pessoa . class , 1 L ) ; p . setNome ( " Marcelo Martins " ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java B.5: AlteraPessoa.java
Execute e consulte o banco de dados atravs do MySQL Workbench! Remova o objeto da classe Pessoa persistido anteriormente. Crie uma classe chamada RemovePessoa dentro de um pacote chamado testes.
8
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
public class RemovePessoa { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_hibernate_envers " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Pessoa p = manager . find ( Pessoa . class , 1 L ) ; manager . remove ( p ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java B.6: RemovePessoa.java
Execute e consulte o banco de dados atravs do MySQL Workbench! Consulte a primeira verso do objeto da classe Pessoa persistido anteriormente. Crie uma classe chamada ConsultaPessoa dentro de um pacote chamado testes.
9
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22
public class ConsultaPessoa { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_hibernate_envers " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; AuditReader reader = AuditReaderFactory . get ( manager ) ; AuditQuery query = reader . createQuery () . forEntitiesAtRevision ( Pessoa . class , 1) ; query . add ( AuditEntity . id () . eq (1 L ) ) ; Pessoa p = ( Pessoa ) query . getSingleResult () ; System . out . println ( p . getNome () ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
132
www.k19.com.br
133
H IBERNATE E NVERS
www.k19.com.br
133
H IBERNATE E NVERS
134
134
www.k19.com.br
APNDICE
Uma tarefa extremamente comum no desenvolvimento de aplicaes JPA a validao dos dados das instncias da entidades. Por exemplo, considere a entidade a seguir.
1 2 3 4 5 6 7 8 9 1 @Entity public class Pessoa { @Id @GeneratedValue private Long id ; private String nome ; }
Cdigo Java C.1: Pessoa.java
Antes de persistir ou atualizar os dados de um objeto de uma classe Pessoa no banco de dados, pode ser necessrio vericar se o atributo nome desse objeto no nulo. Na plataforma Java, uma especicao foi denida para padronizar a tarefa de validao dos objetos do domnio de uma aplicao. O nome dessa especicao Bean Validation e ela pode ser obtida em http://jcp.org/en/jsr/detail?id=3 3. O projeto Hibernate Validator a implementao de referncia da Bean Validation e pode ser obtido em http://www.hibernate.org/ subprojects/validator/download. utilizaremos a verso 4.3.0 do projeto Hibernate Validator. Neste captulo, mostraremos como utilizar os recursos bsicos denidos pela especicao Bean Validation e implementados pelo projeto Hibernate Validator.
Regras de Validao
As regras de validao podem ser denidas atravs de anotaes inseridas nos atributos das entidades. A especicao Bean Validation dene um conjunto padro de anotaes para denir as regras de validao. Veja abaixo as anotaes disponveis e suas respectivas funes. @AssertFalse Verica se uma propriedade booleana possui valor false. @AssertTrue Verica se uma propriedade booleana possui valor true. @DecimalMax Dene o valor real mximo que uma propriedade pode armazenar.
www.k19.com.br
135
136
@DecimalMin Dene o valor real mnimo que uma propriedade pode assumir. @Digits Dene a quantidade mxima de dgitos da parte inteira (atravs do atributo integer) ou da parte fracionria (atravs do atributo fraction) de um nmero. @Future Verica se uma data posterior ao instante atual. @Max Dene o valor inteiro mximo que uma propriedade pode assumir. @Min Dene o valor inteiro mnimo que uma propriedade pode armazenar. @NotNull Verica se o valor de uma propriedade no null. @Null Verica se o valor de uma propriedade null. @Past Verica se uma data anterior ao instante atual. @Pattern Verica se o valor de uma propriedade respeita uma expresso regular. @Size Dene os tamanhos mnimo (atravs do atributo min) e mximo (atravs do atributo max) para uma Collection, array ou String.
Processando as Validaes
As validaes podem ser processadas manualmente pela aplicao atravs do mtodo validate(). Esse mtodo recebe o objeto que desejamos validar e devolve um conjunto com os erros encontrados ou um conjunto vazio caso nenhum erro seja encontrado. Veja o cdigo abaixo.
1 2 3 4 5 6 7 8 9 Pessoa p = . . . ValidatorFactory validatorFactory = Validation . buildDefaultValidatorFactory () ; Validator validator = validatorFactory . getValidator () ; Set < ConstraintViolation < Topico > > errors = validator . validate ( p ) ; for ( ConstraintViolation < Topico > error : errors ) { System . out . println ( error ) ; }
Cdigo Java C.2: Validando um objeto
As validaes podem ser realizadas automaticamente em determinados eventos. Esse comportamento pode ser congurado no arquivo persistence.xml atravs das propriedades:
javax.persistence.validation.group.pre-persist javax.persistence.validation.group.pre-update
136
www.k19.com.br
137
javax.persistence.validation.group.pre-remove
Considere que a propriedade javax.persistence.validation.group.pre-persist esteja congurada no persistence.xml. Nesse caso, os objetos so validados no evento PrePersist, ou seja, quando o mtodo persist() for chamado.
Exerccios de Fixao
Crie um projeto no eclipse chamado K19-Bean-Validation. Copie a pasta lib do projeto K19JPA2-Hibernate para o projeto K19-Bean-Validation.
1
Entre na pasta K19-Arquivos/hibernate-validator-4.3.0.Final/dist da rea de Trabalho e copie os jars dessa pasta e os da pasta lib/required para a pasta lib do projeto K19-Bean-Validation.
2
Depois selecione todos os jars da pasta lib do projeto K19-Bean-Validation e adicione-os no classpath.
3 4 Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-Bean-Validation. Altere o arquivo persistence.xml do projeto K19-Bean-Validation, modi-
cando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 < persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_bean_validation " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_bean_validation " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML C.1: persistence.xml
1 2 3 4 5 6 7 8 9 1
www.k19.com.br
137
138
6 Valide um objeto da classe Pessoa. Crie uma classe chamada ValidaPessoa dentro de um pacote chamado testes.
1 2 3 4 5 6 7 8 9 1 11 12 13 14
public class ValidaPessoa { public static void main ( String [] args ) { Pessoa p = new Pessoa () ; ValidatorFactory validatorFactory = Validation . buildDefaultValidatorFactory () ; Validator validator = validatorFactory . getValidator () ; Set < ConstraintViolation < Pessoa > > errors = validator . validate ( p ) ; for ( ConstraintViolation < Pessoa > error : errors ) { System . out . println ( error ) ; } } }
Cdigo Java C.4: ValidaPessoa.java
Execute e observe as mensagens no Console Congure o Hibernate Validation para que as validaes sejam processadas automaticamente no evento PrePersist. Para isso, altere o arquivo persistence.xml do projeto K19-Bean-Validation. Veja como o cdigo deve car:
7
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24
< persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " > < persistence - unit name = " K21_bean_validation " transaction - type = " RESOURCE_LOCAL " > < provider > org . hibernate . ejb . HibernatePersistence </ provider > < properties > < property name = " hibernate . dialect " value = " org . hibernate . dialect . MySQL5InnoDBDialect " / > < property name = " hibernate . hbm2ddl . auto " value = " update " / > < property name = " hibernate . show_sql " value = " true " / > < property name = " javax . persistence . jdbc . driver " value = " com . mysql . jdbc . Driver " / > < property name = " javax . persistence . jdbc . user " value = " root " / > < property name = " javax . persistence . jdbc . password " value = " root " / > < property name = " javax . persistence . jdbc . url " value = " jdbc:mysql: // localhost:33 6 / K21_bean_validation " / > < property name = " javax . persistence . validation . group . pre - persist " value = " javax . validation . groups . Default " / > </ properties > </ persistence - unit > </ persistence >
Cdigo XML C.2: persistence.xml
Persista um objeto da classe Pessoa. Crie uma classe chamada AdicionaPessoa dentro de um pacote chamado testes.
8
1 2
138
www.k19.com.br
139
3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
www.k19.com.br
139
140
140
www.k19.com.br
APNDICE
No Captulo 2, vimos como o mapeamento objeto-relacional pode ser feito com o uso de anotaes. Esse mesmo mapeamento tambm pode ser denido por meio de um arquivo XML. Neste captulo, veremos como denir o mapeamento no arquivo orm.xml, que deve car no diretrio META-INF no classpath da aplicao. O arquivo orm.xml deve conter a seguinte estrutura.
1 2 3 4 5 6 7 8 9 1 <? xml version = " 1. " encoding = " UTF -8 " ? > < entity - mappings xmlns = " http: // java . sun . com / xml / ns / persistence / orm " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence / orm http: // java . sun . com / xml / ns / persistence / orm_2_ . xsd " version = " 2. " > </ entity - mappings >
Cdigo XML D.1: orm.xml
Todas as regras de mapeamento devem ser especicadas dentro da tag <entity-mappings>. Para simplicar, omitiremos parte do cabealho do arquivo orm.xml nos exemplos apresentados neste captulo.
Entidades
As classes da nossa aplicao que sero mapeadas para tabelas do banco de dados devem ser especicadas no arquivo orm.xml por meio da tag <entity>. Cada instncia de uma entidade deve possuir um identicador nico. Em geral, esse identicador um atributo numrico. No exemplo abaixo, a classe Pessoa possui um atributo chamado id, que ser esse identicador. Esse atributo denido como identicador atravs da tag <id>. Veja o exemplo abaixo.
1 2 3 4 5 6 7 package br . com . k19 ; class Pessoa { private Long id ; // GETTERS E SETTERS }
Cdigo Java D.1: Pessoa.java
1 2 3 4 5 6 7
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " / > </ attributes > </ entity > </ entity - mappings >
www.k19.com.br
141
142
Dessa forma, a coluna correspondente ao atributo id ser denida como chave primria da tabela correspondente classe Pessoa.
Importante
Por padro, quando o mapeamento denido pelo arquivo orm.xml, o modo de acesso aos dados das entidades Property Access. Ou seja, o provedor JPA acessa os dados dos objetos por meio dos mtodos getters e setters dos objetos. Dessa forma, os mtodos getters e setters devem estar implementados. Para alterar esse comportamento, podemos usar o atributo access da tag entity, como mostrado no exemplo abaixo.
1 2 3 4 5 6 7 < entity - mappings > < entity class = " br . com . k19 . Pessoa " access = " FIELD " > < attributes > < id name = " id " / > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.3: orm.xml
Para denir o modo de acesso como sendo Field Access para todas as classes da unidade de persistncia, podemos usar a tag <access>.
1 2 3 4 5 6 7 8 < entity - mappings > < persistence - unit - metadata > < persistence - unit - defaults > < access > FIELD </ access > </ persistence - unit - defaults > </ persistence - unit - metadata > ... </ entity - mappings >
Cdigo XML D.4: orm.xml
Mais detalhes sobre os modos Property Access e Field Access podem ser encontrados adiante.
Por conveno, a classe Pessoa ser mapeada para uma tabela com o mesmo nome (Pessoa). O atributo id ser mapeado para uma coluna com o mesmo nome (id) na tabela Pessoa. As tags <table> e column podem ser usadas para personalizar os nomes das tabelas e das colunas, respectivamente.
1 2 3 4 5 6 7 8 9 1 < entity - mappings > < entity class = " br . com . k19 . Pessoa " > < table name = " tbl_pessoas " / > < attributes > < id name = " id " > < column name = " col_id " / > </ id > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.5: orm.xml
142
www.k19.com.br
143
(a)
(b)
Figura D.1: Tabelas correspondentes classe Pessoa. Em (a), os nomes da tabela e da coluna so padres. Em (b), esses nomes so personalizados.
Denindo Restries
Podemos denir algumas restries para os atributos das nossas entidades atravs das propriedades da tag <column>. Veja as principais propriedades abaixo:
Limita a quantidade de caracteres de uma string Determina se o campo pode possuir valores null ou no Determina se uma coluna pode ter valores repetidos ou no Determina a quantidade de dgitos de um nmero decimal a serem armazenadas Determina a quantidade de casas decimais de um nmero decimal
Tabela D.1: Algumas propriedades da anotao @Column
No exemplo a seguir, associamos trs restries ao atributo nome da classe Pessoa. O nome deve possuir no mximo 30 caracteres, no pode ser nulo e duas pessoas no podem ter o mesmo nome. Alm disso, denimos que a altura das pessoas ser representada por um nmero de trs dgitos, sendo dois deles referentes s casas decimais.
1 2 3 4 5 6 7 package br . com . k19 ; class Pessoa { private Long id ; private String nome ; private BigDecimal altura ; }
Cdigo Java D.2: Pessoa.java
1 2 3 4 5 6 7 8 9 1 11 12 13
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " / > < basic name = " nome " > < column length = " 3 " nullable = " false " unique = " true " / > </ basic > < basic name = " altura " > < column precision = " 3 " scale = " 2 " / > </ basic > </ attributes > </ entity > </ entity - mappings >
www.k19.com.br
143
144
Mapeamento Automtico
Cada banco possui o seu prprio conjunto de tipos de dados. Para que as informaes possam navegar da aplicao para o banco e vice-e-versa, os tipos do Java devem ser mapeados para tipos apropriados do banco de dados. Alguns tipos do Java so mapeados automaticamente para tipos correspondentes do banco de dados. Eis uma lista dos tipos que so mapeados automaticamente:
Tipos primitivos (byte, short, char, int, long, oat, double e boolean) Classes Wrappers (Byte, Short, Character, Integer, Long, Float, Double e Boolean) String BigInteger e BigDecimal java.util.Date e java.util.Calendar java.sql.Date, java.sql.Time e java.sql.Timestamp Array de byte ou char Enums Serializables
145
1 2 3 4 5 6 7 8 9 1 11 12
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " avatar " > < lob / > </ basic > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.8: orm.xml
Data e Hora
Comumente, as aplicaes Java utilizam as classes java.util.Date e java.util.Calendar para trabalhar com datas e horas. Essas classes so mapeadas automaticamente para tipos adequados no banco de dados. Portanto, basta declarar os atributos utilizando um desses dois tipos nas classes que sero mapeadas para tabelas.
1 2 3 4 5 6 package br . com . k19 ; class Pessoa { private Long id ; private Calendar nascimento ; }
Cdigo Java D.4: Pessoa.java
Por padro, quando aplicamos o tipo java.util.Date ou java.util.Calendar, tanto a data quanto a hora sero armazenadas no banco de dados. Para mudar esse comportamento, devemos usar a tag <temporal> escolhendo uma das trs opes abaixo: DATE: Armazena apenas a data (dia, ms e ano).
www.k19.com.br
145
146
1 2 3 4 5 6 7 8 9 1 11 12
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " nascimento " > < temporal > DATE </ temporal > </ basic > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.9: orm.xml
Dados Transientes
Eventualmente, no desejamos que alguns atributos de um determinado grupo de objetos sejam persistidos no banco de dados. Nesse caso, devemos usar a tag <transient>. No exemplo abaixo, usamos a tag <transient> para indicar que o atributo idade no deve ser armazenado no banco de dados. A idade de uma pessoa pode ser deduzida a partir de sua data de nascimento, que j est armazenada no banco.
1 2 3 4 5 6 7 package br . com . k19 ; class Pessoa { private Long id ; private Calendar nascimento ; private int idade ; }
Cdigo Java D.5: Pessoa.java
1 2 3 4 5 6 7 8 9 1 11 12 13
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " nascimento " > < temporal > DATE </ temporal > </ basic > < transient name = " idade " / > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.10: orm.xml
146
www.k19.com.br
147
Figura D.2: Tabela correspondente classe Pessoa. Note que essa tabela no possui nenhuma coluna associada ao atributo idade da classe
Pessoa
Exerccios de Fixao
1 Crie um projeto no Eclipse chamado K19-Mapeamento-XML. Copie a pasta lib do projeto K19JPA2-Hibernate para o projeto K19-Mapeamento-XML. Depois adicione os jars dessa pasta no classpath desse novo projeto.
Abra o MySQL Workbench e apague a base de dados K21_mapeamento_xml_bd se existir. Depois crie a base de dados K21_mapeamento_xml_bd.
2
Copie a pasta META-INF do projeto K19-JPA2-Hibernate para dentro da pasta src do projeto K19-Mapeamento-XML. Altere o arquivo persistence.xml do projeto K19-Mapeamento-XML, modicando o nome da unidade de persistncia e a base da dados. Veja como o cdigo deve car:
3
1 2 3 4 5 6
< persistence version = " 2. " xmlns = " http: // java . sun . com / xml / ns / persistence " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence http: // java . sun . com / xml / ns / persistence / persistence_2_ . xsd " >
www.k19.com.br
147
148
Crie uma entidade para modelar os usurios de uma rede social dentro de um pacote chamado
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27
<? xml version = " 1. " encoding = " UTF -8 " ? > < entity - mappings xmlns = " http: // java . sun . com / xml / ns / persistence / orm " xmlns:xsi = " http: // www . w3 . org /2 1/ XMLSchema - instance " xsi:schemaLocation = " http: // java . sun . com / xml / ns / persistence / orm http: // java . sun . com / xml / ns / persistence / orm_2_ . xsd " version = " 2. " > < entity class = " br . com . k19 . modelo . Usuario " access = " FIELD " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " email " > < column unique = " true " / > </ basic > < basic name = " dataDeCadastro " > < temporal > DATE </ temporal > </ basic > < basic name = " foto " > < lob / > </ basic > </ attributes >
148
www.k19.com.br
149
28 29 3 </ entity > </ entity - mappings >
Cdigo XML D.12: orm.xml
6 Adicione um usurio no banco de dados. Crie uma classe chamada AdicionaUsuario em um pacote chamado br.com.k19.testes do projeto K19-Mapeamento-XML.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
public class AdicionaUsuario { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Usuario usuario = new Usuario () ; usuario . setEmail ( " contato@k19 . com . br " ) ; usuario . setDataDeCadastro ( Calendar . getInstance () ) ; manager . persist ( usuario ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java D.7: AdicionaUsuario.java
Abra o MySQL Workbench e observe as propriedades da tabela Usuario da base de dados K21_mapeamento_xml_bd.
7
Enums
Por padro, os tipos enumerados de JAVA so mapeados para colunas numricas inteiras no banco de dados. Cada elemento de um Enum associado a um nmero inteiro. Essa associao baseada na ordem em que os elementos do Enum so declarados. O primeiro elemento ser associado ao valor 0, o segundo ser associado ao valor 1 e assim por diante. Considere o exemplo a seguir.
1 2 3 4 5 6 package br . com . k19 ; public enum Periodo { MATUTINO , NOTURNO }
Cdigo Java D.8: Periodo.java
1 2 3 4 5 6 7
package br . com . k19 ; public class Turma { private Long id ; private Periodo periodo ; }
www.k19.com.br
149
150
O Enum Periodo possui dois elementos: MATUTINO e NOTURNO. O elemento MATUTINO ser associado ao valor 0 e o elemento NOTURNO ser associado ao valor 1. A tabela correspondente classe Turma possuir um campo chamado periodo. Nos registros correspondentes s turmas de perodo matutino, esse campo possuir o valor 0. J nos registros correspondentes s turmas de perodo noturno, esse campo possuir o valor 1. Imagine que um novo perodo adicionado, digamos, o perodo vespertino. Nesse caso, o Enum
Os valores j armazenados no banco de dados poderiam estar incorretos. Por exemplo, antes dessa modicao, o campo periodo das turmas noturnas deveria armazenar o valor 1. Aps essa modicao, o valor correto passa a ser 2. Assim, os valores do campo periodo da tabela Turma devem ser atualizados de acordo. No entanto, essa atualizao no automtica, e deve ser feita manualmente. Para evitar esse problema, podemos fazer com que os elementos de um Enum sejam associados a uma string ao invs de um nmero inteiro. Isso pode ser feito com o uso da tag <enumerated>. Observe o exemplo abaixo.
1 2 3 4 5 6 7 8 9 1 11 12 < entity - mappings > < entity class = " br . com . k19 . Turma " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " periodo " > < enumerated > STRING </ enumerated > </ basic > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.13: orm.xml
Nesse exemplo, os elementos MATUTINO, VESPERTINO e NOTURNO do Enum Periodo sero associados s strings "MATUTINO", "VESPERTINO" e "NOTURNO", respectivamente.
Colees
Considere um sistema que controla o cadastro dos funcionrios de uma empresa. Esses funcionrios so modelados pela seguinte classe.
150
www.k19.com.br
151
1 2 3 4 5 6 package br . com . k19 ; public class Funcionario { private Long id ; private String nome ; }
Cdigo Java D.11: Funcionario.java
Devemos tambm registrar os telefones de contato dos funcionrios, sendo que cada funcionrio pode ter um ou mais telefones. Em Java, seria razovel utilizar colees para armazenar os telefones dos funcionrios. Veja o exemplo abaixo.
1 2 3 4 5 6 7 package br . com . k19 ; public class Funcionario { private Long id ; private String nome ; private Collection < String > telefones ; }
Cdigo Java D.12: Funcionario.java
1 2 3 4 5 6 7 8 9 1
< entity - mappings > < entity class = " br . com . k19 . Funcionario " > < attributes > < id name = " id " > < generated - value / > </ id > < element - collection name = " telefones " / > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.14: orm.xml
A tag <element-collection> deve ser utilizada para que o mapeamento seja realizado. Nesse exemplo, o banco de dados possuiria uma tabela chamada Funcionario_telefones contendo duas colunas. Uma coluna seria usada para armazenar os identicadores dos funcionrios e a outra para os telefones. Veja uma ilustrao das tabelas do banco de dados na gura abaixo.
A tabela criada para guardar os telefones dos funcionrios tambm pode ter o seu nome personalizado, assim como os nomes de suas colunas. Para isso, devemos usar as tags <collection-table>, <join-column> e <column>.
1 2 3 4 5 < entity - mappings > < entity class = " br . com . k19 . Funcionario " > < attributes > < id name = " id " > < generated - value / >
www.k19.com.br
151
152
Relacionamentos
Os relacionamentos entre as entidades de um domnio devem ser expressos na modelagem atravs de vnculos entre classes. De acordo com a JPA, podemos denir quatro tipos de relacionamentos de acordo com a cardinalidade. One to One (Um para Um): Por exemplo, um estado governado por apenas um governador e um governador governa apenas um estado.
One to Many (Um para Muitos): Por exemplo, um departamento possui muitos funcionrios e um funcionrio trabalha em apenas em um departamento.
Many to One (Muitos para Um): Por exemplo, um pedido pertence a apenas um cliente e um cliente faz muitos pedidos.
Many to Many (Muitos para Muitos): Por exemplo, um livro possui muitos autores e um autor possui muitos livros.
152
www.k19.com.br
153
One to One
Suponha que em nosso domnio existam duas entidades: Estado e Governador. Devemos criar uma classe para cada entidade e editar o arquivo orm.xml de acordo.
1 2 3 4 5 package br . com . k19 ; class Estado { private Long id ; }
Cdigo Java D.13: Estado.java
1 2 3 4 5
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
< entity - mappings > < entity class = " br . com . k19 . Estado " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . Governador " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.16: orm.xml
Como existe um relacionamento entre estados e governadores, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Estado.
1 2 3 4 5 6 7 package br . com . k19 ; class Estado { private Long id ; private Governador governador ; }
Cdigo Java D.15: Estado.java
www.k19.com.br
153
154
Alm disso, devemos informar ao provedor JPA que o relacionamento que existe entre um estado e um governador do tipo One to One. Fazemos isso aplicando usando a tag <one-to-one> no atributo que expressa o relacionamento.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 < entity - mappings > < entity class = " br . com . k19 . Estado " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - one name = " governador " / > </ attributes > </ entity > < entity class = " br . com . k19 . Governador " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.17: orm.xml
No banco de dados, a tabela referente classe Estado possuir uma coluna de relacionamento chamada de join column. Em geral, essa coluna ser denida como uma chave estrangeira associada tabela referente classe Governador. Por padro, o nome da coluna de relacionamento formado pelo nome do atributo que estabelece o relacionamento, seguido pelo caractere _ e pelo nome do atributo que dene a chave primria da entidade alvo. No exemplo de estados e governadores, a join column teria o nome governador_id.
Podemos alterar o nome padro das join columns usando a tag <join-column>, conforme apresentado no exemplo abaixo.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 < entity - mappings > < entity class = " br . com . k19 . Estado " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - one name = " governador " > < join - column name = " gov_id " / > </ one - to - one > </ attributes > </ entity > ... </ entity - mappings >
154
www.k19.com.br
155
Mais Sobre
Por padro, em um relacionamento One to One, um objeto da primeira entidade no precisa estar necessariamente relacionado a um objeto da segunda entidade. Para exigir que cada objeto da primeira entidade esteja relacionado a um objeto da segunda entidade, devemos usar o atributo optional da tag <one-to-one>.
1 2 3 4 5 6 7 8 9 1 11 12 13 < entity - mappings > < entity class = " br . com . k19 . Estado " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - one name = " governador " optional = " false " / > </ attributes > </ entity > ... </ entity - mappings >
Cdigo XML D.19: orm.xml
Exerccios de Fixao
Implemente duas entidades no pacote br.com.k19.modelo do projeto K19-Mapeamento-XML: Estado e Governador.
8
1 2 3 4 5 6
public class Governador { private Long id ; private String nome ; // GETTERS AND SETTERS }
Cdigo Java D.16: Governador.java
1 2 3 4 5 6 7
public class Estado { private Long id ; private String nome ; private Governador governador ; // GETTERS AND SETTERS }
www.k19.com.br
155
156
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19
Adicione um governador e um estado no banco de dados. Crie uma classe chamada AdicionaEstadoGovernador no pacote br.com.k19.testes do projeto K19-Mapeamento-XML.
10
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24
public class AdicionaEstadoGovernador { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Governador g = new Governador () ; g . setNome ( " Rafael Cosentino " ) ; Estado e = new Estado () ; e . setNome ( " So Paulo " ) ; e . setGovernador ( g ) ; manager . persist ( g ) ; manager . persist ( e ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java D.18: AdicionaEstadoGovernador.java
Abra o MySQL Workbench e observe as propriedades das tabelas Estado e Governador da base de dados K21_mapeamento_xml_bd.
11
One to Many
156
www.k19.com.br
157
Suponha que em nosso domnio existam as entidades Departamento e Funcionrio. Criaramos duas classes com as anotaes bsicas de mapeamento.
1 2 3 4 5 package br . com . k19 ; class Departamento { private Long id ; }
Cdigo Java D.19: Departamento.java
1 2 3 4 5
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
< entity - mappings > < entity class = " br . com . k19 . Departamento " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . Funcionario " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.21: orm.xml
Como existe um relacionamento entre departamentos e funcionrios, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Departamento. Supondo que um departamento possa ter muitos funcionrios, devemos utilizar uma coleo para expressar esse relacionamento.
1 2 3 4 5 6 7 package br . com . k19 ; class Departamento { private Long id ; private Collection < Funcionario > funcionarios ; }
Cdigo Java D.21: Departamento.java
Para informar a cardinalidade do relacionamento entre departamentos e funcionrios, devemos usar a tag <one-to-many na coleo.
1 2 3 4 5 < entity - mappings > ... < entity class = " br . com . k19 . Funcionario " > < attributes >
www.k19.com.br
157
158
No banco de dados, alm das duas tabelas correspondentes s classes Departamento e Funcionario, deve existir uma terceira tabela para relacionar os registros dos departamentos com os registros dos funcionrios. Essa terceira tabela chamada de tabela de relacionamento ou join table. Por padro, o nome da join table a concatenao com _ dos nomes das duas entidades. No exemplo de departamentos e funcionrios, o nome do join table seria Departamento_Funcionario. Essa tabela possuir duas colunas vinculadas s entidades que formam o relacionamento. No exemplo, a join table Departamento_Funcionario possuir uma coluna chamada Departamento_id e outra chamada funcionarios_id.
Para personalizar os nomes das colunas da join table e da prpria join table, podemos usar a tag <join-table> no atributo que dene o relacionamento.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 < entity - mappings > ... < entity class = " br . com . k19 . Funcionario " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - many name = " funcionarios " > < join - table name = " DEP_FUNC " > < join - column name = " DEP_ID " / > < inverse - join - column name = " FUNC_ID " / > </ join - table > </ one - to - many > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.23: orm.xml
158
www.k19.com.br
159
Exerccios de Fixao
12
Departamento e Funcionario.
1 2 3 4 5 6 public class Funcionario { private Long id ; private String nome ; // GETTERS AND SETTERS }
Cdigo Java D.22: Funcionario.java
1 2 3 4 5 6 7
public class Departamento { private Long id ; private String nome ; private Collection < Funcionario > funcionarios = new ArrayList < Funcionario >() ; // GETTERS AND SETTERS }
Cdigo Java D.23: Departamento.java
13
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
www.k19.com.br
159
160
14
Abra o MySQL Workbench e observe as propriedades das tabelas Departamento, Funcionario e Departamento_Funcionario da base de dados K21_mapeamento_xml_bd.
15
Many to One
Suponha que em nosso domnio existam as entidades Pedido e Cliente. As duas classes que modelariam essas entidades seriam denidas com as anotaes principais de mapeamento.
1 2 3 4 5 package br . com . k19 ; class Pedido { private Long id ; }
Cdigo Java D.25: Pedido.java
1 2 3 4 5
160
www.k19.com.br
161
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 < entity - mappings > < entity class = " br . com . k19 . Pedido " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . Cliente " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
Como existe um relacionamento entre pedidos e clientes, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Pedido. Supondo que um pedido pertena a um nico cliente, devemos utilizar um atributo simples para expressar esse relacionamento.
1 2 3 4 5 6 package br . com . k19 ; class Pedido { private Long id ; private Cliente cliente ; }
Para informar a cardinalidade do relacionamento entre pedidos e clientes, devemos utilizar a tag <many-to-one>.
1 2 3 4 5 6 7 8 9 1 11 12 13 < entity - mappings > < entity class = " br . com . k19 . Pedido " > < attributes > < id name = " id " > < generated - value / > </ id > < many - to - one name = " cliente " / > </ attributes > </ entity > ... </ entity - mappings >
No banco de dados, a tabela referente classe Pedido possuir uma join column vinculada tabela da classe Cliente. Por padro, o nome da join column formado pelo nome da entidade alvo do relacionamento, seguido pelo caractere _ e pelo nome do atributo que dene a chave primria da entidade alvo.
www.k19.com.br
161
162
No exemplo de pedidos e clientes, o nome da join column seria cliente_id. Podemos alterar o nome padro das join columns usando a tag <join-column>.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 < entity - mappings > < entity class = " br . com . k19 . Pedido " > < attributes > < id name = " id " > < generated - value / > </ id > < many - to - one name = " cliente " > < join - column name = " cli_id " / > </ many - to - one > </ attributes > </ entity > ... </ entity - mappings >
Cdigo XML D.27: orm.xml
Mais Sobre
Por padro, em um relacionamento Many to One, um objeto da primeira entidade no precisa estar necessariamente relacionado a um objeto da segunda entidade. Para exigir que cada objeto da primeira entidade esteja relacionado a um objeto da segunda entidade, devemos usar o atributo optional da tag many-to-one.
1 2 3 4 5 6 7 8 9 1 11 12 13 < entity - mappings > < entity class = " br . com . k19 . Pedido " > < attributes > < id name = " id " > < generated - value / > </ id > < many - to - one name = " cliente " optional = " false " / > </ attributes > </ entity > ... </ entity - mappings >
Cdigo XML D.28: orm.xml
162
www.k19.com.br
163
Exerccios de Fixao
Implemente duas entidades no pacote br.com.k19.modelo do projeto K19-Mapeamento-XML: Pedido e Cliente.
16
1 2 3 4 5 6
public class Cliente { private Long id ; private String nome ; // GETTERS AND SETTERS }
Cdigo Java D.28: Cliente.java
1 2 3 4 5 6 7
public class Pedido { private Long id ; private Calendar data ; private Cliente cliente ; // GETTERS AND SETTERS }
Cdigo Java D.29: Pedido.java
17
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23
Adicione um cliente e um departamento no banco de dados. Crie uma classe chamada AdicionaPedidoCliente no pacote br.com.k19.testes do projeto K19-Mapeamento-XML.
18
1 2 3 4 5 6
public class AdicionaPedidoCliente { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ;
www.k19.com.br
163
164
19 Abra o MySQL Workbench e observe as propriedades das tabelas Cliente e Pedido da base de dados K21_mapeamento_xml_bd.
Many to Many
Suponha que em nosso domnio existam as entidades Livro e Autor. As classes com as anotaes bsicas de mapeamento seriam mais ou menos assim:
1 2 3 4 5 package br . com . k19 ; class Livro { private Long id ; }
Cdigo Java D.31: Livro.java
1 2 3 4 5
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
< entity - mappings > < entity class = " br . com . k19 . Livro " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . Autor " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
164
www.k19.com.br
165
Como existe um relacionamento entre livros e autores, devemos expressar esse vnculo atravs de um atributo que pode ser inserido na classe Livro. Supondo que um livro possa ser escrito por muitos autores, devemos utilizar uma coleo para expressar esse relacionamento.
1 2 3 4 5 6 7 package br . com . k19 ; class Livro { private Long id ; private Collection < Autor > autores ; }
Cdigo Java D.33: Livro.java
Para informar a cardinalidade do relacionamento entre livros e autores, devemos utilizar a tag <many-to-many>.
1 2 3 4 5 6 7 8 9 1 11 12 13 < entity - mappings > < entity class = " br . com . k19 . Livro " > < attributes > < id name = " id " > < generated - value / > </ id > < many - to - many name = " autores " / > </ attributes > </ entity > ... </ entity - mappings >
Cdigo XML D.31: orm.xml
No banco de dados, alm das duas tabelas correspondentes s classes Livro e Autor, uma join table criada para relacionar os registros dos livros com os registros dos autores. Por padro, o nome da join table a concatenao com _ dos nomes das duas entidades. No exemplo de livros e autores, o nome do join table seria Livro_Autor. Essa tabela possuir duas colunas vinculadas s entidades que formam o relacionamento. No exemplo, a join table Livro_Autor possuir uma coluna chamada Livro_id e outra chamada autores_id.
www.k19.com.br
165
166
Para personalizar o nome join table e os nomes de suas colunas, podemos usar a tag <join-table> no atributo que dene o relacionamento.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 < entity - mappings > < entity class = " br . com . k19 . Livro " > < attributes > < id name = " id " > < generated - value / > </ id > < many - to - many name = " autores " > < join - table name = " Liv_Aut " > < join - column name = " Liv_ID " / > < inverse - join - column name = " Aut_ID " / > </ join - table > </ many - to - many > </ attributes > </ entity > ... </ entity - mappings >
Cdigo XML D.32: orm.xml
Exerccios de Fixao
20
Livro e Autor.
1 2 3 4 5 6 public class Autor { private Long id ; private String nome ; // GETTERS AND SETTERS }
Cdigo Java D.34: Autor.java
1 2 3 4 5 6
public class Livro { private Long id ; private String nome ; private Collection < Autor > autores = new ArrayList < Autor >() ; // GETTERS AND SETTERS
166
www.k19.com.br
167
7 }
Cdigo Java D.35: Livro.java
21
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19
Adicione um livro e um autor no banco de dados. Crie uma classe chamada AdicionaLivroAutor no pacote br.com.k19.testes do projeto K19-Mapeamento-XML.
22
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24
public class AdicionaLivroAutor { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Autor a = new Autor () ; a . setNome ( " Rafael Cosentino " ) ; Livro l = new Livro () ; l . setNome ( " JPA2 " ) ; l . getAutores () . add ( a ) ; manager . persist ( a ) ; manager . persist ( l ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java D.36: AdicionaLivroAutor.java
Abra o MySQL Workbench e observe as propriedades das tabelas Livro, Autor e Livro_Autor da base de dados K21_mapeamento_xml_bd.
23
Relacionamentos Bidirecionais
www.k19.com.br
167
168
Quando expressamos um relacionamento colocando um atributo em uma das entidades, podemos acessar a outra entidade a partir da primeira. Por exemplo, considere o relacionamento entre governadores e estados.
1 2 3 4 5 6 class Estado { private Long id ; private Governador governador ; // GETTERS E SETTERS }
Cdigo Java D.37: Estado.java
1 2 3 4 5
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2
< entity - mappings > < entity class = " br . com . k19 . Estado " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - one name = " governador " / > </ attributes > </ entity > < entity class = " br . com . k19 . Governador " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.34: orm.xml
Como o relacionamento est denido na classe Estado, podemos acessar o governador a partir de um estado.
1 2 Estado e = manager . find ( Estado . class , 1 L ) ; Governador g = e . getGovernador () ;
Cdigo Java D.39: Acessando o governador a partir de um estado
Tambm podemos expressar o relacionamento na classe Governador. Dessa forma, poderamos acessar um estado a partir de um governador.
1 2 3 4 5 6 class Governador { private Long id ; private Estado estado ; // GETTERS E SETTERS }
Cdigo Java D.40: Governador.java
168
www.k19.com.br
169
1 2 3 4 5 6 7 8 9 1 11 12 13 < entity - mappings > ... < entity class = " br . com . k19 . Governador " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - one name = " estado " / > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.35: orm.xml
1 2
A gura abaixo ilustra as tabelas Estado e Governador no banco de dados, assim como as join columns correspondentes aos relacionamentos.
Note que foram criadas duas colunas de relacionamentos. A primeira na tabela Estado com o nome governador_id e a segunda na tabela Governador com o nome estado_id. Nesse caso, o provedor JPA est considerando dois relacionamentos unidirecionais distintos entre essas entidades. No entanto, de acordo com o modelo relacional, a relao entre estados e governadores deveria ser expressa com apenas uma coluna de relacionamento. Ou seja, o relacionamento entre governadores e estados deveria ser bidirecional. Assim, devemos indicar em uma das classes que esse relacionamento bidirecional a juno de dois relacionamentos unidirecionais. Para isso, devemos usar o atributo mapped-by da tag <one-to-one> em uma das entidades. O valor do mapped-by deve ser o nome do atributo que expressa o mesmo relacionamento na outra entidade.
1 2 3 4 5 6 7 8 9 1 11 12 13 < entity - mappings > ... < entity class = " br . com . k19 . Governador " > < attributes > < id name = " id " > < generated - value / > </ id > <one - to - one name = " estado " mapped - by = " governador " / > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.36: orm.xml
www.k19.com.br
169
170
Exerccios de Fixao
Considere um sistema de cobrana de ligaes telefnicas. Nesse sistema, temos uma entidade chamada Ligao e uma entidade chamada Fatura. Cada ligao est associada a uma nica fatura, enquanto que uma fatura est associada a mltiplas ligaes. Implemente classes para modelar essas duas entidades em uma pacote chamado br.com.k19.modelo no projeto K19-Mapeamento-XML.
24
1 2 3 4 5 6 7
public class Fatura { private Long id ; private Calendar vencimento ; private Collection < Ligacao > ligacoes = new ArrayList < Ligacao >() ; // GETTERS E SETTERS }
Cdigo Java D.42: Fatura.java
1 2 3 4 5 6 7
public class Ligacao { private Long id ; private Integer duracao ; private Fatura fatura ; // GETTERS E SETTERS }
Cdigo Java D.43: Ligacao.java
25
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23
170
www.k19.com.br
171
24 25 </ entity > ...
Cdigo XML D.37: orm.xml
Crie um teste para adicionar algumas ligaes e uma fatura no pacote br.com.k19.testes no projeto K19-Mapeamento-XML.
26
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28 29 3 31 32 33
public class AdicionaFaturaLigacao { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Ligacao ligacao1 = new Ligacao () ; ligacao1 . setDuracao (162) ; Ligacao ligacao2 = new Ligacao () ; ligacao2 . setDuracao (324) ; Fatura fatura = new Fatura () ; fatura . setVencimento ( new GregorianCalendar (2 12 , 11 , 2 ) ) ; fatura . getLigacoes () . add ( ligacao1 ) ; fatura . getLigacoes () . add ( ligacao2 ) ; ligacao1 . setFatura ( fatura ) ; ligacao2 . setFatura ( fatura ) ; manager . persist ( fatura ) ; manager . persist ( ligacao1 ) ; manager . persist ( ligacao2 ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java D.44: AdicionaFaturaLigacao.java
Atravs do MySQL Workbench, verique as tabelas criadas. Observe que a tabela Ligacao possui uma coluna de relacionamento chamada fatura_id e a tabela Fatura_Ligacao vincula os registros das tabelas Ligacao e Fatura.
27
Atravs do MySQL Workbench, apague primeiro a tabela Fatura_Ligacao e, em seguida, apague as tabelas Fatura e Ligacao.
28
Altere o cdigo do arquivo orm.xml da pasta src/META-INF do projeto K19-Mapeamento-XML de forma a criar um relacionamento bidirecional entre as faturas e as ligaes.
29
1 2 3 4 5 6 7 8 9 1
... < entity class = " br . com . k19 . modelo . Fatura " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " vencimento " > < temporal > DATE </ temporal > </ basic >
www.k19.com.br
171
172
<one - to - many name = " ligacoes " mapped - by = " fatura " / > </ attributes > </ entity > < entity class = " br . com . k19 . modelo . Ligacao " > < attributes > < id name = " id " > < generated - value / > </ id > < many - to - one name = " fatura " / > </ attributes > </ entity > ...
Cdigo XML D.38: orm.xml
Execute a classe AdicionaFaturaLigacao para adicionar a futura e suas ligaes. Atravs do MySQL Workbench, verique as tabelas criadas. Note que foram criadas apenas duas tabelas: Fatura e Ligacao.
30
Objetos Embutidos
Suponha que em nosso domnio exista uma entidade chamada Pessoa. Toda pessoa possui um endereo, que formado por pas, estado, cidade, logradouro, nmero, complemento e CEP. Para melhorar a organizao da nossa aplicao, podemos criar e mapear duas classes: Pessoa e Endereco.
1 2 3 4 5 6 class Pessoa { private Long id ; private String nome ; private Calendar nascimento ; private Endereco endereco ; }
Cdigo Java D.45: Pessoa.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
class Endereco { private Long id ; private String pais ; private String estado ; private String cidade ; private String logradouro ; private int numero ; private String complemento ; private int cep ; }
Cdigo Java D.46: Endereco.java
1 2 3
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes >
172
www.k19.com.br
173
4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 < id name = " id " > < generated - value / > </ id > < basic name = " nascimento " > < temporal > DATE </ temporal > </ basic > <one - to - one name = " endereco " / > </ attributes > </ entity > < entity class = " br . com . k19 . Endereco " > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.39: orm.xml
Da forma como os mapeamentos esto denidos, duas tabelas sero criadas: uma para a classe Pessoa e outra para a classe Endereco. Na tabela Pessoa, haver uma coluna de relacionamento. Para recuperar os dados do endereo de uma pessoa, duas tabelas precisam ser consultadas atravs de uma operao de join. Esse tipo de operao no banco de dados custoso. Suponha que a tabela Endereco esteja relacionada apenas com a tabela Pessoa. Nesse caso, seria interessante se pudssemos guardar os endereos das pessoas na prpria tabela Pessoa, tornando desnecessria a existncia da tabela Endereco. No entanto, gostaramos de manter as classes Pessoa e Endereco. Isso pode ser feito da seguinte forma. No arquivo orm.xml, devemos remover o elemento de cardinalidade <one-to-one> e o mapeamento da entidade Endereco. Alm disso, devemos acrescentar o elemento <embeddable/> para mapear a classe Endereco. Alm disso, no devemos denir uma chave para a classe Endereco, pois ela no dene uma entidade.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 < entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " nascimento " > < temporal > DATE </ temporal > </ basic > </ attributes > </ entity > < embeddable class = " br . com . k19 . Endereco " / > </ entity - mappings >
Cdigo XML D.40: orm.xml
1 2 3 4 5 6
class Endereco { private String pais ; private String estado ; private String cidade ;
www.k19.com.br
173
174
private String logradouro ; private int numero ; private String complemento ; private int cep ; }
Cdigo Java D.47: Endereco.java
Podemos conseguir o mesmo resultado da seguinte forma. Na arquivo orm.xml, devemos substituir o elemento de cardinalidade <One-to-one> por <embedded> e remover o mapeamento da entidade Endereco. Tambm, no devemos denir uma chave para a classe Endereco, pois ela no dene uma entidade.
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 < entity - mappings > < entity class = " br . com . k19 . Pessoa " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " nascimento " > < temporal > DATE </ temporal > </ basic > < embedded name = " endereco " / > </ attributes > </ entity > </ entity - mappings >
Cdigo XML D.41: orm.xml
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
class Endereco { private String pais ; private String estado ; private String cidade ; private String logradouro ; private int numero ; private String complemento ; private int cep ; }
Cdigo Java D.48: Endereco.java
Exerccios de Fixao
Crie uma classe para modelar endereos no pacote br.com.k19.modelo do projeto K19-MapeamentoXML.
31
1 2
174
www.k19.com.br
175
3 4 5 6 7 8 9 1 11 12 private String estado ; private String cidade ; private String logradouro ; private int numero ; // GETTERS AND SETTERS }
Cdigo Java D.49: Endereco.java
1 2 3 4 5 6 7 8 9 1 11
public class Candidato { private Long id ; private String nome ; private Calendar nascimento ; private Endereco endereco ; // GETTERS E SETTERS }
Cdigo Java D.50: Candidato.java
Altere o cdigo do arquivo orm.xml da pasta src/META-INF do projeto K19-Mapeamento-XML de forma a criar um relacionamento bidirecional entre as faturas e as ligaes.
33
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15
... < entity class = " br . com . k19 . modelo . Candidato " > < attributes > < id name = " id " > < generated - value / > </ id > < basic name = " nascimento " > < temporal > DATE </ temporal > </ basic > < embedded name = " endereco " / > </ attributes > </ entity > ...
Cdigo XML D.42: orm.xml
Crie uma classe chamada AdicionaCandidatoEndereco para adicionar alguns candidatos e endereos no pacote br.com.k19.testes do projeto K19-Mapeamento-XML.
34
1 2 3 4 5 6 7 8 9 1
public class AdicionaCandidatoEndereco { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Endereco e = new Endereco () ; e . setEstado ( " So Paulo " ) ;
www.k19.com.br
175
176
Herana
O mapeamento objeto-relacional descreve como os conceitos de orientao a objetos so mapeados para os conceitos do modelo relacional. De todos os conceitos de orientao a objetos, um dos mais complexos de se mapear o de Herana. A especicao JPA dene trs estratgias para realizar o mapeamento de herana. Single Table Joined Table Per Class
Single Table
A estratgia Single Table a mais comum e a que possibilita melhor desempenho em relao a velocidade das consultas. Nessa estratgia, a super classe deve ser mapeada com
<inheritance strategy=SINGLE_TABLE>.
O provedor JPA criar apenas uma tabela com o nome da super classe para armazenar os dados dos objetos criados a partir da super classe ou das sub classes. Todos os atributos da super classe e os das sub classes sero mapeados para colunas dessa tabela. Alm disso, uma coluna especial chamada DTYPE ser utilizada para identicar a classe do objeto correspondente ao registro.
1 2 3 4 5 public class Pessoa { private Long id ; private String nome ; }
Cdigo Java D.52: Pessoa.java
176
www.k19.com.br
177
1 2 3 public class PessoaJuridica extends Pessoa { private String cnpj ; }
Cdigo Java D.53: PessoaJuridica.java
1 2 3
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < inheritance strategy = " SINGLE_TABLE " / > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . PessoaJuridica " > </ entity > < entity class = " br . com . k19 . PessoaFisica " > </ entity > </ entity - mappings >
Cdigo XML D.43: orm.xml
A desvantagem da Single Table o consumo desnecessrio de espao, j que nem todos os campos so utilizados para todos os registros. Por exemplo, se uma pessoa jurdica fosse cadastrada, o campo cpf no seria utilizado. Da mesma forma, se uma pessoa fsica fosse cadastrada, o campo cnpj no seria utilizado.
Joined
Nessa estratgia, uma tabela para cada classe da hierarquia criada. Em cada tabela, apenas os campos referentes aos atributos da classe correspondente so adicionados. Para relacionar os registros das diversas tabelas e remontar os objetos quando uma consulta for realizada, as tabelas relacionadas s sub-classes possuem chaves estrangeiras vinculadas tabela associada super-classe.
www.k19.com.br
177
178
1 2 3
1 2 3
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < inheritance strategy = " JOINED " / > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . PessoaJuridica " > </ entity > < entity class = " br . com . k19 . PessoaFisica " > </ entity > </ entity - mappings >
Cdigo XML D.44: orm.xml
O consumo de espao utilizando a estratgia Joined menor do que o utilizado pela estratgia Single Table. Contudo, as consultas so mais lentas, pois necessrio realizar operaes de join para recuperar os dados dos objetos.
178
www.k19.com.br
179
1 2 3
1 2 3
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
< entity - mappings > < entity class = " br . com . k19 . Pessoa " > < inheritance strategy = " TABLE_PER_CLASS " / > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . PessoaJuridica " > </ entity > < entity class = " br . com . k19 . PessoaFisica " > </ entity > </ entity - mappings >
Cdigo XML D.45: orm.xml
Na estratgia Table Per Class, no podemos utilizar a gerao automtica de chave primrias simples e numricas.
www.k19.com.br
179
180
Exerccios de Fixao
Adicione uma classe chamada Pessoa no pacote br.com.k19.modelo do projeto K19-MapeamentoXML.
35
1 2 3 4 5 6 7
public class Pessoa { private Long id ; private String nome ; // GETTERS E SETTERS }
Cdigo Java D.61: Pessoa.java
1 2 3 4 5
public class PessoaJuridica extends Pessoa { private String cnpj ; // GETTERS E SETTERS }
Cdigo Java D.62: PessoaJuridica.java
37
1 2 3 4 5
Altere o cdigo do arquivo orm.xml da pasta src/META-INF do projeto K19-Mapeamento-XML de forma a criar um relacionamento bidirecional entre as faturas e as ligaes.
38
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18
... < entity class = " br . com . k19 . modelo . Pessoa " > < inheritance strategy = " SINGLE_TABLE " / > < attributes > < id name = " id " > < generated - value / > </ id > </ attributes > </ entity > < entity class = " br . com . k19 . modelo . PessoaJuridica " > </ entity > < entity class = " br . com . k19 . modelo . PessoaFisica " > </ entity > ...
Cdigo XML D.46: orm.xml
180
www.k19.com.br
181
39
Crie um teste para adicionar pessoas. No pacote br.com.k19.testes do projeto K19-MapeamentoXML adicione a seguinte classe:
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19 2 21 22 23 24 25 26 27 28 public class AdicionaPessoa { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_mapeamento_xml_pu " ) ; EntityManager manager = factory . createEntityManager () ; manager . getTransaction () . begin () ; Pessoa p1 = new Pessoa () ; p1 . setNome ( " Marcelo " ) ; PessoaFisica p2 = new PessoaFisica () ; p2 . setNome ( " Rafael " ) ; p2 . setCpf ( " 1234 " ) ; PessoaJuridica p3 = new PessoaJuridica () ; p3 . setNome ( " K19 " ) ; p3 . setCnpj ( " 567788 " ) ; manager . persist ( p1 ) ; manager . persist ( p2 ) ; manager . persist ( p3 ) ; manager . getTransaction () . commit () ; manager . close () ; factory . close () ; } }
Cdigo Java D.64: AdicionaPessoa.java
www.k19.com.br
181
182
182
www.k19.com.br
APNDICE
Cdigo Java 1.4: Autor.java Cdigo Java 1.5: GeraTabelas.java
R ESPOSTAS
1 2 3 4 5 6 7 8
public class GeraTabelas { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_livraria " ) ; factory . close () ; } }
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17
public class InsereAutorComJPA { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_livraria_pu " ) ; EntityManager manager = factory . createEntityManager () ; Autor novoAutor = new Autor () ; Scanner entrada = new Scanner ( System . in ) ; System . out . println ( " Digite o nome do autor : " ) ; novoAutor . setNome ( entrada . nextLine () ) ; manager . persist ( novoAutor ) ;
www.k19.com.br
183
R ESPOSTAS
18 19 2 21 22 23 manager . getTransaction () . begin () ; manager . getTransaction () . commit () ; factory . close () ; } }
Cdigo Java 1.17: InsereAutorComJPA.java
184
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16
public class ListaAutoresComJPA { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_livraria_pu " ) ; EntityManager manager = factory . createEntityManager () ; Query query = manager . createQuery ( " SELECT a FROM Autor a " ) ; List < Autor > autores = query . getResultList () ; for ( Autor a : autores ) { System . out . println ( " AUTOR : " + a . getNome () ) ; } } }
Cdigo Java 1.18: ListaAutoresComJPA.java
1 2 3 4 5 6 7 8 9 1 11 12 13 14 15 16 17 18 19
public class ListaAutores { public static void main ( String [] args ) { EntityManagerFactory factory = Persistence . createEntityManagerFactory ( " K21_criteria_pu " ) ; EntityManager manager = factory . createEntityManager () ; CriteriaBuilder cb = manager . getCriteriaBuilder () ; CriteriaQuery < Autor > c = cb . createQuery ( Autor . class ) ; Root < Autor > l = c . from ( Autor . class ) ; c . select ( l ) ; TypedQuery < Autor > query = manager . createQuery ( c ) ; List < Autor > autores = query . getResultList () ; for ( Autor autor : autores ) { System . out . println ( autor . getNome () ) ; } } }
Cdigo Java 5.10: ListaAutores.java
184
www.k19.com.br