【发布时间】:2021-08-20 16:10:59
【问题描述】:
我正在尝试使用 Spring Boot 进行 Hibernate 关系映射(OneToOne 等)练习。在你问之前,我已经查阅了这个链接:[https://stackoverflow.com/questions/11104897/hibernate-attempted-to-assign-id-from-null-one-to-one-property-employee]。我知道弱实体需要对父实体有一个引用,但我无法弄清楚,为什么我需要在 Person 类构造函数中明确地这样做? 代码如下。
SpringApplication:
package com.OneToOne.OneToOneMappingPractice;
import java.util.Arrays;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
@SpringBootApplication
public class App
{
public static void main( String[] args )
{
ApplicationContext applContext = SpringApplication.run(App.class, args);
String[] beanNames = applContext.getBeanDefinitionNames();
Arrays.sort(beanNames);
for(String beanName : beanNames)
System.out.println(beanName);
}
}
CRUDController.java:
package com.OneToOne.OneToOneMappingPractice;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@CrossOrigin
public class CRUDController
{
private static int randomNumber=(int) Math.random();
@Autowired
private CRUDControllerRepository repository;
@GetMapping(value="/add")
public void add()
{
Person person = new Person("Person"+randomNumber, "Street"+randomNumber, randomNumber);
repository.save(person);
randomNumber+=1;
}
@GetMapping(value="/getAll")
public List<Person> getAll()
{
return repository.findAll();
}
@DeleteMapping(value="/deleteAll")
public void deleteAll()
{
repository.deleteAll();
}
}
Person.java:
package com.OneToOne.OneToOneMappingPractice;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.PrimaryKeyJoinColumn;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
@Entity
public class Person
{
private String name;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private int Id;
@OneToOne(mappedBy="person", cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
private Address address;
public Person() {}
public Person(String name, String streetName, int house_number)
{
super();
this.name = name;
this.address=new Address();
this.address.setStreetName(streetName);
this.address.setHouse_number(house_number);
//this.address.setPerson(this);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return Id;
}
public void setId(int id) {
Id = id;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
地址.java:
package com.OneToOne.OneToOneMappingPractice;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.MapsId;
import javax.persistence.OneToOne;
@Entity
public class Address {
@Id
@Column(name="user_id")
private int Id;
private int house_number;
private String streetName;
@OneToOne
@MapsId
@JoinColumn(name = "user_id")
private Person person;
public Address(){}
public int getHouse_number() {
return house_number;
}
public void setHouse_number(int house_number) {
this.house_number = house_number;
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
this.streetName = streetName;
}
// public Person getPerson() {
// return person;
// }
public void setPerson(Person person) {
this.person = person;
}
}
CRUDControllerRepository.java:
package com.OneToOne.OneToOneMappingPractice;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
@Repository
@Transactional
public interface CRUDControllerRepository extends JpaRepository<Person, Integer>
{
Person save(Person person);
void deleteAll();
List<Person> findAll();
}
以下是我的问题:
- 如您所见,在 Person 类参数化构造函数中,我已将以下行注释掉:this.address.setPerson(this);。如果我将此行注释掉,我会收到异常:“尝试从空的一对一属性 [com.OneToOne.OneToOneMappingPractice.Address.person] 分配 id;嵌套异常是 org.hibernate.id.IdentifierGenerationException:尝试从空的一对一属性分配 id [com.OneToOne.OneToOneMappingPractice.Address.person]”。如果我删除注释语法,它会完美运行。为什么我需要明确地这样做? @OneToOne 注释不应该自己处理这些引用吗?
2.如果我在 Address 类中启用 Person getPerson() 方法,它会递归继续,直到堆栈爆炸:“无法为请求呈现错误页面 [/getAll] 和异常 [无法编写 JSON:无限递归(StackOverflowError);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException"。 为什么 Hibernate 本身不能确定它需要自己停止在该边界处,而不是再次获取父对象?
我是否在这里遗漏了有关这些映射注释或其他任何内容?
【问题讨论】:
标签: java spring spring-boot hibernate