Bidirecional simples @OneToOne store null
Tento seguir o exemplo bidrecional @OneToOne da documentação, mas sempre tenho uma referência nula na coluna PhoneDetails phone_id e obtein um Phone com detalhes nulos quando faço um get.
Eu sigo a documentação criando classes Phone e PhoneDetails como está escrito.
Mas como a documentação não especifica como testar e preciso desenvolver um aplicativo Spring Boot, crio um para testar e talvez, em qualquer etapa deste, tenha o erro.
Aqui estão minhas etapas e o código que atualizo para o github, esperando que alguém possa revisá-lo
1 - Crie um aplicativo Spring Boot no Eclipse com conjunto de ferramentas Spring com Java Versão 8
2 - Adicionar dependências MySqlDriver e Spring Web
3 - Adicionar dependência no pom para spring-boot-starter-data-jpa
4 - Crie pacotes no pacote principal (com.onetoone) para modelos, controladores e repositório
5 - Crie no pacote do modelo as classes Phone e PhoneDetails conforme digamos no pacote de documentação com.onetoone.models;
@Entity(name = "Phone")
public class Phone {
@Id
@GeneratedValue
private Long id;
@Column(name = "`number`")
private String number;
@OneToOne(
mappedBy = "phone",
cascade = CascadeType.ALL,
orphanRemoval = true,
fetch = FetchType.LAZY
)
private PhoneDetails details;
//Getters and setters are omitted for brevity
public void addDetails(PhoneDetails details) {
details.setPhone( this );
this.details = details;
}
public void removeDetails() {
if ( details != null ) {
details.setPhone( null );
this.details = null;
}
}
}
@Entity(name = "PhoneDetails")
public class PhoneDetails {
@Id
@GeneratedValue
private Long id;
private String provider;
private String technology;
@OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "phone_id")
private Phone phone;
//Getters and setters are omitted for brevity
}
Na documentação, eles criam essas classes como estáticas, mas tenho que removê-las porque o Eclipse diz: "Modificador ilegal para a classe Phone; apenas público, abstrato e final são permitidos". Eu importo todas as anotações (@Entity, @Id ...) de javax.persistence.
6 - Crie a interface PhoneController em seu pacote
package com.onetoone.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.onetoone.models.Phone;
public interface PhoneRepository extends JpaRepository<Phone, Long> {
}
7 - Criar PhoneController
package com.onetoone.controllers;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.onetoone.models.Phone;
import com.onetoone.repository.PhoneRepository;
@RestController
@RequestMapping("/phone")
public class PhoneController {
@Autowired
PhoneRepository phoneRepository;
@PostMapping("/save")
public ResponseEntity<Boolean> savePhone(@RequestBody Phone phone) {
phoneRepository.save(phone);
return ResponseEntity.ok(true);
}
@PostMapping("/get")
public ResponseEntity<Optional<Phone>> getPhone(@RequestBody int i) {
Long id = Long.valueOf(i);
Optional<Phone> phone = phoneRepository.findById(id);
return ResponseEntity.ok(phone);
}
}
8 - Defina o application.properties em seu arquivo em src / main / resources
spring.datasource.url= jdbc:mysql://localhost:3306/test?serverTimezone=UTC
spring.datasource.username= root
spring.jpa.properties.hibernate.dialect= org.hibernate.dialect.MySQL5Dialect
spring.jpa.hibernate.ddl-auto= update
Tenho que adicionar? ServerTimezone = UTC ao url do banco de dados para evitar um erro.
9 - Crie um esquema em meu banco de dados local chamado teste
10 - Inicie o aplicativo com Spring Boot Dashboard e crie as tabelas 'phone' e 'phone_details' (também outra chamada 'hibernate_sequence')
11- Eu uso o carteiro para mandar um resto para este url http: // localhost: 8080 / telefone / salvar neste corpo
{
"number": "123-456-7890",
"details": {
"provider": "T-Mobile",
"technology": "GSM"
}
}
12 - E aqui está o problema. Ele cria uma entrada na tabela do telefone (id, número)
'1', '123-456-7890'
e outro na tabela phone_details (id, provedor, tecnologia, phone_id)
'2', 'T-Mobile', 'GSM', NULL
13 - Claro, se eu postar na url http: // localhost: 8080 / phone / get with body 1 eu recibo
{
"id": 1,
"number": "123-456-7890",
"details": null
}
Espero que alguém possa me ajudar porque tento reduzir o código ao mínimo para seguir a documentação e ainda tenho o problema :-(
A solução dada por @JavaMan é suficiente para o exemplo, mas não para um objeto complexo. Espero que mais alguém possa me ajudar !!!
Respostas
No seu PhoneController, você deve adicionar a linha phone.getDetails (). SetPhone (phone); caso contrário, o objeto de detalhes não terá uma referência ao telefone.
Assim assim
@PostMapping("/save")
public ResponseEntity<Boolean> savePhone(@RequestBody Phone phone) {
phone.getDetails().setPhone(phone);
phoneRepository.save(phone);
return ResponseEntity.ok(true);
}
Além disso, para obter o código em execução, adicione a @JsonIgnoreanotação ao campo Phone na classe PhoneDetails.