问题描述
我正在使用 MysqL 数据库制作 Spring Boot 应用程序,并且我正在尝试设置类似这个示例的内容(针对问题进行了简化) 其中一些可选实体可以保存有关用户的额外数据。
这是我设置的简化示例: 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" );
}
如果有人有更好的解决方案,我仍然会感兴趣。但这暂时有效。