外键未在Spring Rest应用程序中保存

时间:2018-02-15 10:51:13

标签: hibernate rest spring-data-jpa spring-restcontroller spring-rest

我正在尝试使用Spring Data JPA实现双向一对多关系。我已经创建了用于保存和获取数据的测试用例,并且映射中没有问题,并且数据被保存在两个表中。 但是当我尝试通过点击Post请求来创建数据时,外键没有被保存。客户和电话之间的映射是双向的一对多。

以下是我的代码。 1) 包com.jwt.onetomany;

import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication 公共类OneToMany1Application {

public static void main(String[] args) {
    SpringApplication.run(OneToMany1Application.class, args);
}

}

2)

package com.jwt.onetomany.controller;

import java.net.URI;
import java.util.List;

import org.apache.tomcat.jni.Poll;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.support.ServletUriComponentsBuilder;

import com.jwt.onetomany.entity.Customer;
import com.jwt.onetomany.repo.CustomerRepository;

@RestController
public class DemoController {

    @Autowired
    CustomerRepository customerRepository;

    @GetMapping("/getall")
    ResponseEntity<List<Customer>> getAllCustomers() {

        Iterable<Customer> findAll = customerRepository.findAll();
        List<Customer> customers = (List<Customer>) findAll;
        return new ResponseEntity<List<Customer>>(customers, HttpStatus.OK);

    }

    @PostMapping(path = "/customers", produces = MediaType.APPLICATION_XML_VALUE)
    public ResponseEntity<?> createPoll(@RequestBody Customer customer) {

        customerRepository.save(customer);

        // Set the location header for the newly created resource
        HttpHeaders responseHeaders = new HttpHeaders();
        URI newPollUri = ServletUriComponentsBuilder.fromCurrentRequest().path("/{id}").buildAndExpand(customer.getId())
                .toUri();
        responseHeaders.setLocation(newPollUri);

        return new ResponseEntity<>(null, responseHeaders, HttpStatus.CREATED);
    }

}

3)

package com.jwt.onetomany.entity;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;

@Entity
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private long id;
    private String name;

    @OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Set<PhoneNumber> phoneNumbers;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(Set<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    public void addPhoneNumber(PhoneNumber number) {
        if (number != null) {
            if (phoneNumbers == null) {
                phoneNumbers = new HashSet<>();
            }
            number.setCustomer(this);
            phoneNumbers.add(number);
        }
    }

}

4)

package com.jwt.onetomany.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

import com.fasterxml.jackson.annotation.JsonIgnore;

@Entity
@Table(name="phone_number")
public class PhoneNumber {

    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long id;
    private String number;
    private String type;

    @ManyToOne
    @JoinColumn(name = "customer_id")
    @JsonIgnore
    private Customer customer;

    public long getId() {
        return id;
    }

    public void setId(long id) {
        this.id = id;
    }

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public Customer getCustomer() {
        return customer;
    }

    public void setCustomer(Customer customer) {
        this.customer = customer;
    }

}

5)

package com.jwt.onetomany.repo;

import org.springframework.data.repository.CrudRepository;

import com.jwt.onetomany.entity.Customer;

public interface CustomerRepository extends CrudRepository<Customer, Long> {

}

数据库使用是mysql

SQL脚本

CREATE TABLE customer(   id int(11)NOT NULL AUTO_INCREMENT,   name varchar(20)DEFAULT NULL,   主要关键(id) )ENGINE = InnoDB AUTO_INCREMENT = 13 DEFAULT CHARSET = utf8;

6) CREATE TABLE phone_number(   id int(11)NOT NULL AUTO_INCREMENT,   customer_id int(11)DEFAULT NULL,   number varchar(20)DEFAULT NULL,   type varchar(20)DEFAULT NULL,   PRIMARY KEY(id),   KEY FK1j552es3t8oswmbjr0rw15ew6customer_id),   约束FK1j552es3t8oswmbjr0rw15ew6外键(customer_id)参考customerid),   约束phone_number_ibfk_1外键(customer_id)参考customerid) )ENGINE = InnoDB AUTO_INCREMENT = 13 DEFAULT CHARSET = utf8;

3 个答案:

答案 0 :(得分:1)

删除mappedBy = "customer"属性,并将@JoinColumn(name = "customer_id")注释添加到Customer类中的Set<PhoneNumber>

可以选择从@JoinColumn类中删除PhoneNumber注释。

mappedBy属性指定该关系由另一个类拥有。因此,在上述情况下,添加外键的责任在于子类。用@JoinColumn注释替换它指定关系的所有权与父类一起使用。

参考:JPA JoinColumn vs mappedBy

答案 1 :(得分:0)

您无法使用外键显示哪个数据。假设您需要显示值意味着要使用外键手动进行数据处理。

答案 2 :(得分:0)

“删除“ mappedBy =”客户“属性,并在客户类中添加@JoinColumn(name =” customer_id“)批注”

在这种情况下,这似乎可以解决在子表(phone_number)中生成外键的问题,但是该解决方案将在内部回退到OnetoMany单向关系,其中jpa生成的查询数量将为2n + 1。

在“客户”类中执行以下操作:

@OneToMany(mappedBy = "customer", cascade = CascadeType.ALL, fetch = FetchType.EAGER)
@JsonManagedReference(value = "cust_phone")
private Set<PhoneNumber> phoneNumbers;

以及在PhoneNumber类中:

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "customer_id")
@JsonIgnore
@JsonBackReference(value = "cust_phone")
private Customer customer;

这将正确设置外键,并且生成的查询数也为N + 1。