我正在尝试使用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
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 FK1j552es3t8oswmbjr0rw15ew6
(customer_id
),
约束FK1j552es3t8oswmbjr0rw15ew6
外键(customer_id
)参考customer
(id
),
约束phone_number_ibfk_1
外键(customer_id
)参考customer
(id
)
)ENGINE = InnoDB AUTO_INCREMENT = 13 DEFAULT CHARSET = utf8;
答案 0 :(得分:1)
删除mappedBy = "customer"
属性,并将@JoinColumn(name = "customer_id")
注释添加到Customer类中的Set<PhoneNumber>
。
可以选择从@JoinColumn
类中删除PhoneNumber
注释。
mappedBy
属性指定该关系由另一个类拥有。因此,在上述情况下,添加外键的责任在于子类。用@JoinColumn
注释替换它指定关系的所有权与父类一起使用。
答案 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。