Simple Bidireccional @OneToOne store null

Nov 07 2020

Intento seguir el ejemplo bidreccional @OneToOne de la documentación, pero siempre tengo una referencia nula en la columna PhoneDetails phone_id, y obtengo un teléfono con detalles nulos cuando obtengo.

Sigo la documentación que crea las clases Phone y PhoneDetails como se dice.

Pero debido a que la documentación no especifica cómo probar y necesito desarrollar una aplicación Spring Boot, creo una para probar y tal vez, en cualquier paso de esto, tenga el error.

Estos son mis pasos y el código que actualizo a github con la esperanza de que alguien pueda revisarlo

1 - Cree una aplicación Spring Boot en Eclipse con el conjunto de herramientas Spring con Java Versión 8

2 - Agregar dependencias MySqlDriver y Spring Web

3 - Agregue dependencia en el pom a spring-boot-starter-data-jpa

4 - Cree paquetes en el paquete principal (com.onetoone) para modelos, controladores y repositorio

5 - Cree en el paquete del modelo las clases Phone y PhoneDetails como se indica en el paquete de documentación 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

}

En la documentación, crean estas clases como estáticas, pero tengo que eliminarlas porque Eclipse dice: "Modificador ilegal para la clase Teléfono; solo se permiten públicos, abstractos y finales". Importo todas las anotaciones (@Entity, @Id ...) de javax.persistence.

6 - Crear interfaz PhoneController en su paquete

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

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

7 - Crear 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 - Establezca application.properties en su archivo en 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

Tengo que agregar el? ServerTimezone = UTC a la URL de la base de datos para evitar un error.

9 - Crea un esquema en mi base de datos local llamado prueba

10 - Inicie la aplicación con Spring Boot Dashboard, y cree las tablas 'phone' y 'phone_details' (también otra llamada 'hibernate_sequence')

11- Uso cartero para enviar un descanso a esta url http: // localhost: 8080 / phone / save whit this body

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

12 - Y aquí está el problema. Crea una entrada en la tabla de teléfonos (id, número)

'1', '123-456-7890'

y otros en la tabla phone_details (id, proveedor, tecnología, phone_id)

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

13 - Por supuesto, si hago una publicación en la url http: // localhost: 8080 / phone / get con body 1 recibo

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

Espero que alguien pueda ayudarme porque trato de reducir el código al mínimo para seguir la documentación y aún tengo el problema :-(

La solución dada por @JavaMan es suficiente para el ejemplo, pero no para un objeto complejo. Espero que alguien más pueda ayudarme !!!

Respuestas

JavaMan Nov 08 2020 at 09:04

En su PhoneController, debe agregar la línea phone.getDetails (). SetPhone (phone); de lo contrario, el objeto de detalles no tendrá una referencia al teléfono.

Asi que asi

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

Además, para que el código se ejecute, agregue la @JsonIgnoreanotación a su campo Teléfono en su clase PhoneDetails.