Escolar Documentos
Profissional Documentos
Cultura Documentos
E WEB SERVICES
Camada de dados:
ORM e persistência
Sumário
Camada de Dados: ORM e persistência...............................................................................................3
1.1 Padrão ORM (Object-Relational Mapping)...................................................................................3
1.1.1 Mapeamento Relacional..............................................................................................................4
1.1.1.1 Mapeando os relacionamentos entre as entidades....................................................................6 25
1.1.1.1.1 Relacionamentos 1:n.............................................................................................................6
1.1.1.1.2 Relacionamentos 1:1.............................................................................................................7
1.1.1.1.3 Relacionamentos n:n.............................................................................................................9
1.1.2 Mapeamento Objeto-Relacional (ORM)....................................................................................10
1.2 Hibernate e JPA............................................................................................................................10
1.2.1 Hibernate e JPA em projetos Spring Boot.................................................................................11
Atividade............................................................................................................................................21
Referências.........................................................................................................................................22
CAMADA DE DADOS: ORM E PERSISTÊNCIA
25
As tabelas do banco de dados deste sistema podem então ser definidas seguindo-se as
seguintes regras:
1. Para cada entidade, é criada uma tabela correspondente, seguindo algumas
regras de nomenclatura – para a entidade Produto, será criada a tabela produto; para
a entidade Usuario será criada a tabela usuario; para a entidade OrdemDeCompra
será criada a tabela ordem_de_compra e, para a entidade Item, será criada a tabela
item;
2. Para cada atributo de cada entidade, é criada uma coluna na tabela
correspondente (falaremos sobre os tipos de dados mais à frente), seguindo-se
também um padrão de nomenclatura – será criada, por exemplo, na tabela
ordem_de_compra, a coluna data_da_compra;
3. Cada tabela deve ter uma chave primária. No exemplo demonstrado a seguir, foi
criada uma chave primária para cada tabela, de nome id;
4. Por último, é feito o mapeamento dos relacionamentos entre as entidades,
conforme tipo e cardinalidade do relacionamento, o que veremos na subseção a
seguir.
1.1.1.1 Mapeando os relacionamentos entre as en'dades
25
Como no exemplo do nosso sistema de compras online não há nenhum relacionamento 1:1
(lê-se um para um), consideremos o exemplo a seguir:
Figura 3 - Relacionamento 1:1 exemplo: Modelo ER
Fonte: autora
25
Esse Modelo ER exemplo nos diz que um Servidor dirige nenhum ou um Campus (1) e um
Campus é dirigido por um Servidor (1). Temos, portanto, um relacionamento 1:1.
Em um relacionamento 1:1, escolhe-se uma das tabelas para receber uma chave estrangeira
que referenciará uma coluna da outra tabela. Nesse caso, então, tanto faz se servidor receber uma
chave estrangeira ou se campus receber. Contudo, como no exemplo Campus obrigatoriamente
deve ser dirigido por um Servidor e nem todo Servidor irá dirigir um Campus, escolheremos a
tabela campus para receber a chave estrangeira.
O Modelo Relacional resultante, portanto, ficaria como demostrado abaixo:
25
Figura 5 - Relacionamento n:n exemplo: Modelo ER
Fonte: autora
O Modelo ER exemplo nos diz que uma Conta pertence a um ou muitos Cliente (n) e um
Cliente possui nenhuma ou muitas Conta (n). Temos, então, um relacionamento n:n.
Para mapear um relacionamento n:n, uma outra tabela é então definida, chamada de tabela
de relacionamento. Essa tabela irá conter duas chaves estrangeiras, cada uma referenciando a
chave primária de cada uma das tabelas do relacionamento.
O Modelo Relacional ficaria, portanto, conforme demonstrado abaixo:
Para se utilizar Hibernate e JPA em projetos Spring Boot, deve-se seguir um conjunto de
quatro passos que serão descritos a seguir.
1o passo: incluir nas dependências do projeto o Spring Data JPA e o Driver JDBC do SGBD
a ser utilizado – no exemplo, utilizaremos MySQL, então incluiremos no projeto a dependência
MySQL Driver. Para isso, realize os seguintes passos:
i. Abra o arquivo build.gradle, localizado na pasta raiz do projeto;
ii. Em "dependencies", adicionaremos a dependência Spring Data JPA, que é
necessária em tempo de implementação (“implementation”), e a dependência
MySQL Driver, que é necessária em tempo de execução (runtime), acrescentando as
instruções abaixo:
implementa'on 'org.springframework.boot:spring-boot-starter-data-jpa'
run'meOnly 'mysql:mysql-connector-java'
2o passo: configurar os parâmetros para conexão com o banco de dados (BD) – antes de
realizar esse passo, é necessário ter criado um banco de dados que irá receber as tabelas geradas
pelo Hibernate e, posteriormente, os dados da aplicação – isso pode ser feito utilizando-se o
MySQL Workbench. Para configuração dos parâmetros para conexão com o BD, siga os seguintes
passos:
i. Abra o arquivo application.properties, localizado na pasta do projeto
src/main/resources;
ii. Devemos indicar neste arquivo:
a) O modo de criação das tabelas, que irá determinar a estratégia adotada pelo
Hibernate para geração das tabelas do banco de dados durante o
desenvolvimento e que pode ser um dentre os seguintes modos:
create – quando a aplicação for iniciada, as tabelas do banco de dados 25
serão criadas, caso não existam;
create-drop – quando a aplicação for iniciada, as tabelas serão
criadas, caso não existam, e, ao ser finalizada, as tabelas do banco de
dados serão excluídas (é recomendado que esse modo não seja
utilizado em ambiente de produção);
update – semelhante ao modo create, porém verifica-se também se há
a necessidade de criação de novas colunas nas tabelas (esse modo é o
mais recomendado para ambiente de desenvolvimento);
none – nenhuma alteração no banco de dados é feita. Esse é o valor
default e, portanto, assumido caso não seja especificado
Em ambiente de desenvolvimento, é comum utilizar o modo update. Para isso,
deve-se incluir no arquivo application.properties a seguinte definição:
spring.jpa.hibernate.ddl-auto=update
b) A URL para conexão com o banco de dados. Adicionaremos então ao
arquivo application.properties, a declaração – considerando que o banco de
dados criado tem nome telefonia e que o servidor de banco de dados esteja em
execução na máquina local, porta 3306:
spring.datasource.url=jdbc:mysql://localhost:3306/telefonia
c) Usuário e senha para acesso ao banco de dados. Adicionaremos, também
em application.properties, a declaração – considerando que o nome do usuário
é adminTel e a senha é 1234telAdmin:
spring.datasource.username=adminTel
spring.datasource.password=1234telAdmin
d) O nome do driver JDBC para conexão com o banco de dados (mesmo
utilizando JPA, o driver JDBC é necessário, pois toda implementação de ORM
utiliza internamente JDBC). Adicionaremos, também em
application.properties, a declaração – considerando que estamos utilizando o
SGBD MySQL: 25
spring.datasource.driver-class-name = com.mysql.jdbc.Driver
3o passo: mapear as classes que implementam as entidades do sistema, conforme as etapas
descritas a seguir:
i. Para cada classe, adicionar um @En'ty acima da declaração da classe, conforme
demonstrado no exemplo abaixo, indicando para o Hibernate que se trata de uma
entidade do sistema e que ele deverá mapear uma tabela correspondente – para isso,
é necessário importar a classe javax.persistence.En'ty:
import javax.persistence.En'ty;
@En'ty
public class Plano{
}
ii. Indicar para qual atributo da classe será criada uma chave estrangeira. Neste caso, a
estratégia mais adotada é criar, para cada classe, um atributo inteiro id e deve-se,
então, adicionar a esse atributo a anotação @Id. Caso queira que esse id seja gerado
automaticamente, adicionar a anotação
@GeneratedValue(strategy=Genera'onType.AUTO), conforme exemplo abaixo –
para isso, é necessário importar as classes javax.persistence.GeneratedValue,
javax.persistence.Genera'onType e javax.persistence.Id:
public class Plano{
@Id
@GeneratedValue(strategy=Genera'onType.AUTO)
private long id;
}
iii. Para os atributos dos tipos Date ou Calendar é necessário ainda adicionar a anotação
@Temporal, especificando que se trata de um dado temporal, e especificando ainda
um dos três tipos temporais: 25
a) TemporalType.DATE – quando se deseja armazenar somente a data;
b) TemporalType.TIME – quando se deseja armazenar somente a hora;
c) TemporalType.TIMESTAMP – quando se deseja armazenar data e hora.
Exemplo:
public class Ligacao{
@Temporal(TemporalType.TIMESTAMP)
private Date data;
}
iv. Outras anotações podem ser usadas para especificar configurações diferentes das
default, como, por exemplo, nome de tabela, nome de coluna, etc – confira exemplos
em https://www.baeldung.com/jpa-entities.
4o passo: mapear os relacionamentos entre as classes. O mapeamento deve ser feito
conforme cardinalidade e se o relacionamento é uni ou bidirecional. Relacionamentos de herança
também deverão ter um tratamento especial. Portanto, em resumo, o que se faz é analisar as
características do relacionamento para determinar quais alterações deverão ser feitas nas classes que
implementam as entidades envolvidas no relacionamento, conforme é listado a seguir:
i. Para relacionamentos um-para-muitos (1:n ou one-to-many):
a) Se o relacionamento é unidirecional:
Na entidade correspondente ao todo do relacionamento, no atributo cujo
tipo é correspondente à parte do relacionamento, adicionaremos a
anotação @OneToMany, conforme exemplo apresentado a seguir;
É necessário também informar que deve ser criada uma chave
estrangeira na tabela correspondente à parte do relacionamento (relação
n) – do contrário, o Hibernate irá gerar uma tabela de relacionamentos,
o que não é necessário. A tabela de relacionamentos é necessária
somente em relacionamentos n:n. Para isso, adiciona-se ao mesmo
atributo citado anteriormente a anotação
@JoinColumn(name="nome_da_classe_id"). 25
Exemplo:
@En'ty
public class Operadora{
@OneToMany
@JoinColumn(name="operadora_id")
Set<Plano> planos;
}
b) Se o relacionamento é bidirecional:
Na classe correspondente à parte do relacionamento, adicionaremos a
anotação @ManyToOne – com isso, uma chave estrangeira será criada
na tabela correspondente;
Exemplo: considere como exemplo um relacionamento bidirecional 1:n
entre Cliente-Endereco, onde Cliente possui n Endereços, um Endereço
pertence a um Cliente e Cliente é o todo do relacionamento:
@En'ty
public class Endereco{
@ManyToOne
Cliente cliente;
}
Já na classe correspondente ao todo do relacionamento, adicionaremos
a anotação @OneToMany e especificaremos que o relacionamento está
sendo mapeado através da chave estrangeira
(mappedBy=nome_do_atributo_correspondente), conforme exemplo
apresentado abaixo:
@En'ty
public class Cliente{
@OneToMany(mappedBy="cliente")
Set<Endereco> enderecos; 25
}
ii. Para relacionamentos muitos-para-um (n:1 ou many-to-one):
a) Se o relacionamento é unidirecional:
Deve-se adicionar, na classe correspondente ao todo do relacionamento,
no atributo cujo tipo é correspondente à parte do relacionamento, a
anotação @ManyToOne:
Exemplo: considere, como exemplo, que Endereco esteja relacionado a um
Cliente e Cliente pode estar relacionado a n Endereços, porém desconheça
seus Endereços – o todo do relacionamento, neste caso, é Endereco e não
Cliente:
@En'ty
public class Endereco{
@ManyToOne
Cliente cliente;
}
b) Se o relacionamento é bidirecional: é semelhante ao relacionamento um-para-
muitos bidirecional.
iii. Para relacionamentos muitos-para-muitos (n:n ou many-to-many):
a) Se o relacionamento é unidirecional:
Deve-se adicionar, na classe correspondente ao todo do relacionamento, ao
atributo cujo tipo é correspondente à parte do relacionamento, a anotação
@ManyToMany:
Exemplo: considere como exemplo o relacionamento entre Conta-Cliente, em
que uma Conta pode estar relacionada a muitos Clientes, um Cliente pode
estar relacionado a muitas Contas, Conta é o todo do relacionamento e Cliente
desconhece suas Contas (relacionamento unidirecional):
@En'ty
public class Conta{ 25
@ManyToMany
Set<Cliente> clientes;
}
b) Se o relacionamento é bidirecional:
Ambas as classes do relacionamento receberão, em seus atributos
correspondentes, a anotação @ManyToMany a, na classe correspondente à
parte do relacionamento, indicar um mappedBy, conforme exemplo
apresentado abaixo:
Exemplo: considerando o exemplo anterior, considere agora que Cliente
conhece suas Contas (relacionamento bidirecional). Temos, portanto:
@En'ty @En'ty
public class Conta{ public class Cliente{
@ManyToMany @ManyToMany(mappedBy = "clientes")
Set<Cliente> clientes; Set<Conta> contas;
} }
}
E, nas subclasses, devemos adicionar a anotação
@DiscriminatorValue(value="nome_do_valor_dado_a_registros_da_en'dade"),
determinando assim qual o valor para a coluna descriminatória os registros
daquela classe terão. Exemplos:
@En'ty
@DiscriminatorValue(value="ClientePessoaFisica")
public class ClientePessoaFisica{
@En'ty
@DiscriminatorValue(value="ClientePessoaJuridica")
public class ClientePessoaJuricica{
}
Considerando, portanto, os exemplos apresentados, uma única tabela será criada
para as classes Cliente, ClientePessoaFisica e ClientePessoaJuridica. Essa
tabela conterá uma coluna para cada atributo da classe Cliente, uma coluna para
cada atributo definido em ClientePessoaFisica, uma coluna para cada atributo
definido em ClientePessoaJuridica e uma coluna “descriminatória” de nome
class. Registros de ClientePessoaFisica serão armazenados guardando-se em
class o valor ClientePessoaFisica e registros de ClientePessoaJuridica serão
armazenados guardando-se em class o valor ClientePessoaJuridica. Dessa forma,
todos os registros de ClientePessoaFisica, por exemplo, podem ser obtidos a
partir da execução da query SELECT * FROM cliente WHERE class =
‘ClientePessoaFisica’. 25
A'vidade
4) Rode a aplicação. Ao término da execução da aplicação, caso você tenha feito as configurações e
implementações corretamente, você deverá observar que algumas tabelas são geradas pelo
Hibernate (no banco de dados telefonia), conforme Mapeamento Objeto-Relacional descrito neste
material. Analise cada uma das tabelas geradas.
REFERÊNCIAS
WEBB, Phillip et al. Spring boot reference guide. Spring Boot features, v. 24, 2013.