🚀 Capítulo 19: Relacionamentos em JPA
🎯 Objetivo da Aula
Ao final desta aula, você será capaz de mapear relacionamentos entre tabelas de banco de dados utilizando as anotações @ManyToOne e @OneToMany do JPA no Spring Boot.
🏢 O Cenário Prático (Seu Desafio)
Você está mapeando a galáxia de Star Wars! O seu desafio é criar um sistema onde possamos cadastrar Planetas (como Tatooine ou Coruscant) e Personagens (como Luke Skywalker ou Obi-Wan). Como um planeta pode ter muitos personagens nascidos nele, precisamos criar um relacionamento entre essas duas entidades no banco de dados.
🧠 Fundamentos: A Teoria Traduzida
No mundo real e nos bancos de dados relacionais, as informações se relacionam.
- @ManyToOne (Muitos para Um): Muitos personagens pertencem a um único planeta. (Ex: Luke e Anakin pertencem a Tatooine). Esta é a anotação mais comum e cria a chave estrangeira no banco.
- @OneToMany (Um para Muitos): Um único planeta possui muitos personagens associados a ele.
No banco de dados, isso se traduz em uma Chave Estrangeira (Foreign Key) na tabela de personagens apontando para o ID da tabela de planetas.
Diagrama de Relacionamento
erDiagram PLANETA ||--o{ PERSONAGEM : possui PLANETA { Long id String nome } PERSONAGEM { Long id String nome Long planeta_id }
📖 Exemplo Guiado
Vamos criar o relacionamento Many-to-One entre Personagem e Planeta.
🛠️ Passo a Passo para Criar o Projeto no VS Code
- Abra o VS Code.
- Pressione as teclas
Ctrl + Shift + P. - Digite
Spring Initializr: Create Maven Projecte pressioneEnter. - Selecione a versão do Spring Boot e a linguagem
Java. - Group ID:
com.starwarse Artifact ID:galaxia. - Selecione a versão do Java instalada.
- Dependências: Busque e adicione
Spring Web,Spring Data JPAeH2 Database. Pressione Enter. - Gere o projeto e abra no VS Code.
📂 Estrutura Inicial de Pastas
galaxia/
├── src/
│ └── main/
│ ├── java/
│ │ └── com/starwars/galaxia/
│ │ └── GalaxiaApplication.java
│ └── resources/
│ └── application.properties
└── pom.xmlSiga os passos para criar as entidades relacionadas:
- Crie a entidade
Planeta.javana pastacom/starwars/galaxia/:
package com.starwars.galaxia;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
@Entity
public class Planeta {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
public Planeta() {}
public Planeta(String nome) { this.nome = nome; }
public Long getId() { return id; }
public String getNome() { return nome; }
}- Crie a entidade
Personagem.javacom o relacionamento:
package com.starwars.galaxia;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.JoinColumn;
@Entity
public class Personagem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String nome;
@ManyToOne // Muitos personagens para um planeta
@JoinColumn(name = "planeta_id") // Nome da coluna da chave estrangeira no banco
private Planeta planeta;
public Personagem() {}
public Personagem(String nome, Planeta planeta) {
this.nome = nome;
this.planeta = planeta;
}
public Long getId() { return id; }
public String getNome() { return nome; }
public Planeta getPlaneta() { return planeta; }
}🕹️ Como Executar e Testar no VS Code
- Abra o arquivo
GalaxiaApplication.java. - Clique em Run logo acima do método
main. - Como este exemplo foca no mapeamento das entidades, o principal resultado é a criação automática das tabelas no banco de dados.
Resultado Esperado:
O Spring Boot iniciará com sucesso. Se você acessar o console do H2 (conforme configurado em capítulos anteriores), verá que as tabelas PLANETA e PERSONAGEM foram criadas, e a tabela PERSONAGEM possui uma coluna PLANETA_ID que serve como chave estrangeira (Foreign Key).
🛠️ Prática Obrigatória 1
Crie as interfaces PlanetaRepository e PersonagemRepository que herdam de JpaRepository. Crie um PlanetaController com um método @PostMapping para cadastrar novos planetas.
🛠️ Prática Obrigatória 2
Crie um PersonagemController com um método @PostMapping para cadastrar novos personagens. Lembre-se de que para salvar o personagem associado a um planeta, você precisará buscar o planeta pelo ID primeiro!
📤 Instruções de Entrega (GitHub Desktop + Microsoft Teams)
Neste curso, você entregará suas atividades enviando o código para o seu repositório no GitHub usando o aplicativo GitHub Desktop. Siga o passo a passo detalhado:
- Verifique a estrutura: Certifique-se de que sua estrutura de pastas final está idêntica à mostrada abaixo.
- Abra o GitHub Desktop: Certifique-se de que o repositório do seu curso está selecionado no canto superior esquerdo.
- Visualize as alterações: Na aba Changes (à esquerda), você verá todos os arquivos que criou ou modificou nesta aula.
- Faça o Commit:
- No campo Summary (na parte inferior esquerda), digite uma mensagem curta descrevendo o que fez, ex:
Finaliza atividades do Capítulo 19. - Clique no botão azul Commit to main (ou o nome da sua branch).
- No campo Summary (na parte inferior esquerda), digite uma mensagem curta descrevendo o que fez, ex:
- Envie para a Nuvem (Push): No topo da tela, clique no botão Push origin. Isso enviará seu código do seu computador para o seu perfil no GitHub.
- ⚠️ IMPORTANTE (Repositório Público): Para que o professor consiga corrigir, o seu repositório no GitHub DEVE SER PÚBLICO. Repositórios privados não podem ser visualizados por quem não foi convidado.
- Como entregar no Microsoft Teams:
- Copie o link do seu repositório no GitHub (ex:
https://github.com/seu-usuario/seu-repositorio). - Abra a tarefa correspondente no Microsoft Teams.
- Clique no botão Adicionar trabalho (ou Add work).
- Selecione a opção Link no menu lateral.
- Cole o link do GitHub no campo “Endereço Web” e digite um texto (ex:
Meu Repositório) no campo “Texto a ser exibido”. - Clique em Anexar.
- MUITO IMPORTANTE: Clique no botão Entregar (ou Turn in) no canto superior direito para concluir o envio!
- Copie o link do seu repositório no GitHub (ex:
📂 Estrutura Final de Pastas
galaxia/
├── src/
│ └── main/
│ ├── java/
│ │ └── com/starwars/galaxia/
│ │ ├── GalaxiaApplication.java
│ │ ├── Planeta.java
│ │ ├── Personagem.java
│ │ ├── PlanetaRepository.java
│ │ ├── PersonagemRepository.java
│ │ ├── PlanetaController.java
│ │ └── PersonagemController.java
│ └── resources/
│ └── application.properties
└── pom.xml💡 Checkpoint de Lógica
O que você acabou de fazer é mapear a complexidade do mundo real. Quase nenhuma tabela em um sistema real vive sozinha. Clientes têm pedidos, pedidos têm itens, itens têm categorias. Saber relacionar essas tabelas no Java é o que diferencia um programador júnior de um pleno!
🔥 Desafio de Fixação (Opcional)
Pesquise como fazer o relacionamento inverso: adicione uma lista de personagens na classe Planeta usando a anotação @OneToMany(mappedBy = "planeta").
🔑 Gabarito de Código/Fórmulas
Prática 1:
public interface PlanetaRepository extends JpaRepository<Planeta, Long> {}
@RestController
public class PlanetaController {
@Autowired
private PlanetaRepository repo;
@PostMapping("/planetas")
public Planeta criar(@RequestBody Planeta p) {
return repo.save(p);
}
}Prática 2:
@RestController
public class PersonagemController {
@Autowired
private PersonagemRepository repoPer;
@Autowired
private PlanetaRepository repoPla;
@PostMapping("/personagens")
public Personagem criar(@RequestBody PersonagemDTO dto) {
// Busca o planeta pelo ID enviado no DTO
Planeta p = repoPla.findById(dto.getPlanetaId()).get();
Personagem per = new Personagem(dto.getNome(), p);
return repoPer.save(per);
}
}Desafio:
// Na classe Planeta:
@OneToMany(mappedBy = "planeta")
private List<Personagem> personagens;