Simple Bidirectional @OneToOne store null

半城伤御伤魂 提交于 2020-12-13 03:46:10

问题


I try to follow the @OneToOne bidrectional example from documetation but I always have a null reference in the PhoneDetails phone_id colum, and obtein a Phone with null details when do a get.

I follow the documentation creating Phone and PhoneDetails Classes as is say.

But because the documentation don't specify how to test and I need to develop an Spring Boot app, I create one to test and maybe, in any step of this I have the error.

Here are my steps, and the code I update to github hoping someone can review it

1 - Create a Spring Boot App in Eclipse with Spring tool suite with Java Version 8

2 - Add dependencies MySqlDriver and Spring Web

3 - Add dependency in the pom to spring-boot-starter-data-jpa

4 - Create packages under the main package (com.onetoone) for models, controllers and repository

5 - Create in the model package the classes Phone y PhoneDetails as say in documentation package 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

}

In documentation they create this classes as static, but I have to remove it because Eclipse says: "Illegal modifier for the class Phone; only public, abstract & final are permitted". I import all the anotations (@Entity, @Id...) from javax.persistence.

6 - Create interface PhoneController in his 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 - Create 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 - Set the application.properties in his file under 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

I have to add the ?serverTimezone=UTC to the database url to avoid an error.

9 - Create an schema in my local database called test

10 - Start the app with Spring Boot Dashboard, and it create the tables 'phone' and 'phone_details' (also another one called 'hibernate_sequence')

11- I use postman to send a rest to this url http://localhost:8080/phone/save whit this body

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

12 - And here is the problem. It create an entry in the phone table (id, number)

'1', '123-456-7890'

and other in the phone_details table (id, provider, technology, phone_id)

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

13 - Of course, if I do a post to url http://localhost:8080/phone/get with body 1 I recibe

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

I hope anybody can help me because I try to reduce the code to the minimun to follow the documentation and still I have the issue :-(

The solution gives by @JavaMan is enought for the example, but not for a complex object. I hope someoneelse can help me!!!


回答1:


In your PhoneController, you have to add the line phone.getDetails().setPhone(phone); otherwise the details object will not have a reference to the phone.

So like this

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

Also, to get the code running add the @JsonIgnore annotation to your Phone field in your PhoneDetails class.



来源:https://stackoverflow.com/questions/64733460/simple-bidirectional-onetoone-store-null

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!