Simple Bidirectional @OneToOne store null

Nov 07 2020

ฉันพยายามทำตามตัวอย่างทวิภาคของ @OneToOneจากเอกสาร แต่ฉันมักจะมีการอ้างอิงที่เป็นโมฆะในคอลัมน์ PhoneDetails phone_id และ obtein ในโทรศัพท์ที่มีรายละเอียดว่างเมื่อได้รับ

ฉันทำตามเอกสารการสร้างคลาส Phone และ PhoneDetails ตามที่พูด

แต่เนื่องจากเอกสารไม่ได้ระบุวิธีการทดสอบและฉันต้องการพัฒนาแอป Spring Boot ฉันจึงสร้างแอปขึ้นมาเพื่อทดสอบและในขั้นตอนใดก็ตามฉันมีข้อผิดพลาด

นี่คือขั้นตอนของฉันและรหัสที่ฉันอัปเดตเป็น githubหวังว่าจะมีคนตรวจสอบได้

1 - สร้าง Spring Boot App ใน Eclipse ด้วยชุดเครื่องมือ Spring ด้วย Java เวอร์ชัน 8

2 - เพิ่มการอ้างอิง MySqlDriver และ Spring Web

3 - เพิ่มการพึ่งพาใน pom ไปยัง spring-boot-starter-data-jpa

4 - สร้างแพ็คเกจภายใต้แพ็กเกจหลัก (com.onetoone) สำหรับโมเดลคอนโทรลเลอร์และที่เก็บ

5 - สร้างในแพ็กเกจโมเดลคลาส Phone y PhoneDetails ตามที่กล่าวไว้ในแพ็คเกจเอกสาร 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

}

ในเอกสารประกอบพวกเขาสร้างคลาสนี้เป็นแบบคงที่ แต่ฉันต้องลบออกเพราะ Eclipse บอกว่า: "ตัวดัดแปลงที่ผิดกฎหมายสำหรับโทรศัพท์คลาสอนุญาตให้ใช้เฉพาะสาธารณะนามธรรมและขั้นสุดท้ายเท่านั้น" ฉันนำเข้า anotations ทั้งหมด (@Entity, @Id ... ) จาก javax.persistence

6 - สร้างอินเตอร์เฟส PhoneController ในแพ็คเกจของเขา

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

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

7 - สร้าง 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 - ตั้งค่า application.properties ในไฟล์ของเขาภายใต้ 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

ฉันต้องเพิ่ม? serverTimezone = UTC ใน url ของฐานข้อมูลเพื่อหลีกเลี่ยงข้อผิดพลาด

9 - สร้างสคีมาในฐานข้อมูลท้องถิ่นของฉันที่เรียกว่าการทดสอบ

10 - เริ่มแอพด้วย Spring Boot Dashboard และสร้างตาราง 'phone' และ 'phone_details' (หรืออีกอันที่เรียกว่า 'hibernate_sequence')

11- ฉันใช้บุรุษไปรษณีย์เพื่อส่งส่วนที่เหลือไปยัง URL นี้ http: // localhost: 8080 / โทรศัพท์ / บันทึกเนื้อหานี้

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

12 - และนี่คือปัญหา สร้างรายการในตารางโทรศัพท์ (id, number)

'1', '123-456-7890'

และอื่น ๆ ในตาราง phone_details (id, ผู้ให้บริการ, เทคโนโลยี, phone_id)

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

13 - แน่นอนว่าถ้าฉันโพสต์ไปที่ url http: // localhost: 8080 / phone / get with body 1 ฉันรู้สึกตัว

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

ฉันหวังว่าใครก็ได้สามารถช่วยฉันได้เพราะฉันพยายามลดรหัสเป็น minimun เพื่อทำตามเอกสาร แต่ฉันก็ยังมีปัญหาอยู่ :-(

วิธีแก้ปัญหาโดย @JavaMan นั้นเพียงพอสำหรับตัวอย่าง แต่ไม่ใช่สำหรับวัตถุที่ซับซ้อน หวังว่าจะมีใครช่วยได้นะ !!!

คำตอบ

JavaMan Nov 08 2020 at 09:04

ใน PhoneController คุณต้องเพิ่ม line phone.getDetails (). setPhone (โทรศัพท์); มิฉะนั้นวัตถุรายละเอียดจะไม่มีการอ้างอิงถึงโทรศัพท์

อย่างนี้

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

นอกจากนี้ในการเรียกใช้รหัสให้เพิ่ม@JsonIgnoreคำอธิบายประกอบลงในฟิลด์โทรศัพท์ของคุณในคลาส PhoneDetails ของคุณ