Magasin bidirectionnel simple @OneToOne null
J'essaie de suivre l' exemple bidirectionnel @OneToOne de la documentation, mais j'ai toujours une référence nulle dans la colonne PhoneDetails phone_id, et j'obtein un téléphone avec des détails nuls lors d'un get.
Je suis la documentation créant des classes Phone et PhoneDetails comme on dit.
Mais comme la documentation ne spécifie pas comment tester et que j'ai besoin de développer une application Spring Boot, j'en crée une pour la tester et peut-être qu'à n'importe quelle étape de cela, j'ai l'erreur.
Voici mes étapes et le code que je mets à jour vers github en espérant que quelqu'un puisse l'examiner
1 - Créez une application Spring Boot dans Eclipse avec la suite d'outils Spring avec Java version 8
2 - Ajouter des dépendances MySqlDriver et Spring Web
3 - Ajouter une dépendance dans le pom à spring-boot-starter-data-jpa
4 - Créer des packages sous le package principal (com.onetoone) pour les modèles, les contrôleurs et le référentiel
5 - Créez dans le package modèle les classes Phone et PhoneDetails comme par exemple dans le package de documentation 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
}
Dans la documentation, ils créent ces classes comme statiques, mais je dois les supprimer car Eclipse dit: "Modificateur illégal pour la classe Phone; seuls public, abstract et final sont autorisés". J'importe toutes les annotations (@Entity, @Id ...) de javax.persistence.
6 - Créer l'interface PhoneController dans son package
package com.onetoone.repository;
import org.springframework.data.jpa.repository.JpaRepository;
import com.onetoone.models.Phone;
public interface PhoneRepository extends JpaRepository<Phone, Long> {
}
7 - Créer 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 - Définissez le fichier application.properties dans son fichier sous 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
Je dois ajouter le? ServerTimezone = UTC à l'URL de la base de données pour éviter une erreur.
9 - Créer un schéma dans ma base de données locale appelée test
10 - Démarrez l'application avec Spring Boot Dashboard et créez les tables 'phone' et 'phone_details' (également une autre appelée 'hibernate_sequence')
11- J'utilise postman pour envoyer un repos à cette url http: // localhost: 8080 / phone / save whit this body
{
"number": "123-456-7890",
"details": {
"provider": "T-Mobile",
"technology": "GSM"
}
}
12 - Et voici le problème. Il crée une entrée dans la table de téléphone (id, numéro)
'1', '123-456-7890'
et autres dans la table phone_details (id, provider, technology, phone_id)
'2', 'T-Mobile', 'GSM', NULL
13 - Bien sûr, si je fais un post sur l'url http: // localhost: 8080 / phone / get avec body 1 je recibe
{
"id": 1,
"number": "123-456-7890",
"details": null
}
J'espère que tout le monde pourra m'aider car j'essaie de réduire le code au minimum pour suivre la documentation et j'ai toujours le problème :-(
La solution donnée par @JavaMan est suffisante pour l'exemple, mais pas pour un objet complexe. J'espère que quelqu'un d'autre pourra m'aider !!!
Réponses
Dans votre PhoneController, vous devez ajouter la ligne phone.getDetails (). SetPhone (phone); sinon, l'objet de détails n'aura pas de référence au téléphone.
Alors comme ça
@PostMapping("/save")
public ResponseEntity<Boolean> savePhone(@RequestBody Phone phone) {
phone.getDetails().setPhone(phone);
phoneRepository.save(phone);
return ResponseEntity.ok(true);
}
De plus, pour exécuter le code, ajoutez l' @JsonIgnoreannotation à votre champ Phone dans votre classe PhoneDetails.