微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Spring JPA 共享主键导致 org.hibernate.AssertionFailure: null identifier

如何解决Spring JPA 共享主键导致 org.hibernate.AssertionFailure: null identifier

我正在使用 MysqL 数据库制作 Spring Boot 应用程序,并且我正在尝试设置类似这个示例的内容(针对问题进行了简化)

enter image description here

其中一些可选实体可以保存有关用户的额外数据。

这是我设置的简化示例: Person.java:

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OnetoOne;
import javax.persistence.PrimaryKeyJoinColumn;

@Entity
public class Person {

    @Id
    @Column
    @GeneratedValue
    private Long id;

    @Column
    private String name;

    @OnetoOne(cascade = CascadeType.ALL,mappedBy = "person",optional = true)
    @PrimaryKeyJoinColumn
    private Car car;

    //getters,setters and constructors
    public Person() {
        super();
    }
    public Person(Long id,String name) {
        super();
        this.id = id;
        this.name = name;
    }
    public Person(Long id,String name,Car car) {
        super();
        this.id = id;
        this.name = name;
        this.car = car;
    }
    public Long getId() { return id; }
    public String getName() { return name; }
    public Car getCar() { return car; }
    public void setCar(Car car) { this.car = car; }
    public void setId(Long id) { this.id = id; }
    public void setName(String name) { this.name = name; }
}

Car.java:

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 Car {
    @Id
    @Column
    private Long id;
    
    @MapsId
    @OnetoOne //NOTE A
    @JoinColumn(name ="id")
    private Person person;

    @Column
    private String brand;

    //Getters,setters and constructors
    public Car() {
        super();
    }
    public Car(Long id,Person person,String brand) { 
        super();
        this.id = id;
        this.person = person;
        this.brand = brand;
    }
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    public Person getPerson() { return person; }
    public void setPerson(Person person) { this.person = person; }
    public String getBrand() { return brand; }
    public void setBrand(String brand) { this.brand = brand; }

}

还有我的测试课:

@SpringBoottest
class BasicOnetoOneTest  {

    @Autowired
    PersonRepo persons;
    @Autowired
    CarRepo cars;

    @Test
    void test() {
        Person dave = new Person(null,"Dave");
        persons.save(dave);
    
        Car car = new Car(dave.getId(),dave,"HAS_WHEELS");
        cars.save(car);

        dave = persons.findById(dave.getId()).get();
        assertEquals(true,dave.getCar() != null );
    
        cars.delete(car);
    
        dave = persons.findById(dave.getId()).orElseGet(()->null);
        assertEquals(true,dave!=null ); //NOTE B
    }

}

按原样运行时,我得到 org.hibernate.AssertionFailure: null identifier 如果我将 @OnetoOne(在 note A 处)更改为包含 cascade = CascadeType.ALL 空标识符消失了,但该人也被删除了。 (在注 B 处测试)

感谢您的帮助,谢谢:)

解决方法

找到解决办法 我发现运行测试如下:

@Test
void test() {
    Person dave = new Person(null,"Dave");
    persons.save(dave);
    
    Car car = new Car(dave.getId(),dave,"HAS_WHEELS");
    dave.setCar(car); //car is set into the parent entity
    persons.save(dave); //person is saved instead of the car
    
    
    dave = persons.findById(dave.getId()).get(); 
    assertEquals(true,dave.getCar() != null );
    
    cars.delete(car);
    
    dave = persons.findById(dave.getId()).orElseGet(()->null); //skip?
    assertEquals(true,dave!=null );
}

编辑: 此处未按预期删除汽车

编辑: 将 @OneToOne 更改为使用 MERGE 而不是 ALL 似乎有效

    @OneToOne(cascade = CascadeType.MERGE,mappedBy = "person",optional = true)
    @PrimaryKeyJoinColumn
    private Car car;

这是我改后使用的测试:

@Test
    void test2() {
        Person dave = new Person(null,"Dave");
        persons.save(dave);
        
        Car car = new Car(dave.getId(),"HAS_WHEELS");
        
        dave.setCar(car);
        persons.save(dave);
        
        dave = persons.findById(dave.getId()).get(); 
        assertEquals(true,dave.getCar() != null,"Dave does not have car assigned");
        
        cars.delete(car);
        
        
        dave = persons.findById(dave.getId()).orElseGet(()->null);
        assertEquals(true,dave!=null,"Dave deleted" );
        
        assertEquals( false,cars.existsById(car.getId()),"Car not deleted" );
    }

如果有人有更好的解决方案,我仍然会感兴趣。但这暂时有效。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。