【问题标题】:Hibernate Error : attempted to assign id from null one-to-one property. Why?休眠错误:试图从空的一对一属性分配 id。为什么?
【发布时间】: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();
}

以下是我的问题:

  1. 如您所见,在 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


    【解决方案1】:

    1- 如您所见,在 Person 类参数化构造函数中,我 已注释掉这一行:this.address.setPerson(this);。如果我保持 这行注释掉了,我得到了异常:“试图分配 id 从 null 一对一属性

    Hibernate 不会显式设置它,因为它不知道这个地址属于哪个人,你需要显式指定它。

    @OneToOne 的目的是告诉 hibernate 在已经映射后从哪里获取其余数据。

    2.如果我在 Address 类中启用 Person getPerson() 方法,它会递归继续,直到堆栈爆炸:“无法呈现错误 请求页面 [/getAll] 和异常 [无法编写 JSON: 无限递归(StackOverflowError);嵌套异常是 com.fasterxml.jackson.databind.JsonMappingException”。为什么不能 Hibernate 自己确定它需要停在那个边界 本身,而不是再次获取父对象?

    异常是由 Jackson 序列化程序引起的,而不是由休眠引起的。 你可以看看这里的例子,看看它是如何修复的https://www.baeldung.com/jackson-bidirectional-relationships-and-infinite-recursion

    【讨论】:

      猜你喜欢
      • 2017-10-22
      • 2021-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-16
      • 2021-12-18
      • 2019-11-28
      • 1970-01-01
      相关资源
      最近更新 更多