Simple Bidirectional @OneToOne store null

Nov 07 2020

Provo a seguire l' esempio bidirezionale @OneToOne da documetation ma ho sempre un riferimento nullo nella colonna PhoneDetails phone_id e ottengo un telefono con dettagli nulli quando eseguo un get.

Seguo la documentazione creando le classi Phone e PhoneDetails come si dice.

Ma poiché la documentazione non specifica come testare e ho bisogno di sviluppare un'app Spring Boot, ne creo una per testare e forse, in qualsiasi passaggio di questo, ho l'errore.

Ecco i miei passaggi e il codice che aggiorno a GitHub sperando che qualcuno possa esaminarlo

1 - Crea un'app Spring Boot in Eclipse con la suite di strumenti Spring con Java versione 8

2 - Aggiungi le dipendenze MySqlDriver e Spring Web

3 - Aggiungi la dipendenza nel pom a spring-boot-starter-data-jpa

4 - Creare pacchetti nel pacchetto principale (com.onetoone) per modelli, controller e repository

5 - Creare nel pacchetto modello le classi Phone y PhoneDetails come si dice nel pacchetto di documentazione 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

}

Nella documentazione creano queste classi come statiche, ma devo rimuoverle perché Eclipse dice: "Modificatore illegale per la classe Phone; sono consentiti solo public, abstract e final". Importo tutte le annotazioni (@Entity, @Id ...) da javax.persistence.

6 - Crea l'interfaccia PhoneController nel suo pacchetto

package com.onetoone.repository;
import org.springframework.data.jpa.repository.JpaRepository;   
import com.onetoone.models.Phone;

public interface PhoneRepository extends JpaRepository<Phone, Long> {
}

7 - Crea 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 - Imposta application.properties nel suo file sotto 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

Devo aggiungere? ServerTimezone = UTC all'URL del database per evitare un errore.

9 - Crea uno schema nel mio database locale chiamato test

10 - Avvia l'app con Spring Boot Dashboard e crea le tabelle 'phone' e 'phone_details' (anche un'altra chiamata 'hibernate_sequence')

11- Uso il postino per inviare una pausa a questo URL http: // localhost: 8080 / phone / save whit this body

{
  "number": "123-456-7890",
  "details": {
    "provider": "T-Mobile",
    "technology": "GSM"
  }
}

12 - Ed ecco il problema. Crea una voce nella tabella del telefono (id, numero)

'1', '123-456-7890'

e altro nella tabella phone_details (id, provider, tecnologia, phone_id)

'2', 'T-Mobile', 'GSM', NULL

13 - Ovviamente, se faccio un post all'URL http: // localhost: 8080 / phone / get with body 1 lo ricevo

{
    "id": 1,
    "number": "123-456-7890",
    "details": null
}

Spero che qualcuno possa aiutarmi perché cerco di ridurre il codice al minimo per seguire la documentazione e ancora ho il problema :-(

La soluzione fornita da @JavaMan è sufficiente per l'esempio, ma non per un oggetto complesso. Spero che qualcun altro possa aiutarmi !!!

Risposte

JavaMan Nov 08 2020 at 09:04

Nel tuo PhoneController, devi aggiungere la linea phone.getDetails (). SetPhone (phone); altrimenti l'oggetto dettagli non avrà un riferimento al telefono.

Quindi così

@PostMapping("/save")
public ResponseEntity<Boolean> savePhone(@RequestBody Phone phone) {
    phone.getDetails().setPhone(phone); 
    phoneRepository.save(phone);
    return ResponseEntity.ok(true);
}

Inoltre, per eseguire il codice, aggiungi l' @JsonIgnoreannotazione al campo Telefono nella classe PhoneDetails.