【发布时间】:2020-07-10 22:56:34
【问题描述】:
考虑以下几点:
@Entity
@Table(name = "cars")
public class Car {
@Id
private int id;
private String name;
@OneToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, mappedBy = "ownerCar")
private Set<Wheel> wheels = new HashSet<>();
private Car() {
}
public Car(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getId() {
return id;
}
public Set<Wheel> getWheels() {
return wheels;
}
}
@Entity
@Table(name = "wheels")
public class Wheel {
@Id
private int id;
@ManyToOne
private Car ownerCar;
private Wheel() {
}
public Wheel(int id) {
this.id = id;
}
public int getId() {
return id;
}
public Car getOwnerCar() {
return ownerCar;
}
public void setOwnerCar(Car ownerCar) {
this.ownerCar = ownerCar;
}
}
@Override //CommandLineRunner
public void run(String... args) throws Exception {
Car car = new Car(1);
car.setName("Ferrari");
Wheel wheel = new Wheel(1);
wheel.setOwnerCar(car);
car.getWheels().add(wheel);
carService.saveCar(car);
// Assume we have found the car already
car = carService.getById(1).get();
// Load the wheels of this car
carService.loadWheelsForCar(car);
System.out.println(car.getWheels().size());
}
上面的代码会抛出org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: test.app.Car.wheels。
我的问题是如何实现loadWheelsForCar(Car c)方法,而无需再次找车。
换句话说,如何SELECT * FROM WHEELS WHERE owner_car_id = car.id 并将结果添加到集合中。我可能可以手动完成,但这是唯一的方法吗?
我知道当没有活动会话时会抛出LazyInitializationException(@Transactional 不会导致创建新会话吗?)。我尝试过:
@Transactional
public void loadWheelsForCar(Car c) {
c.getWheels().size(); // will load wheels
}
但抛出异常。
如果是XY problem,我不这样做的原因(CarService):
@Transactional
public Optional<Car> getByIdWithWheels(int carId) {
Optional<Car> possibleCar = carRepository.findById(carId);
possibleCar.ifPresent(c -> c.getWheels().size());
return possibleCar;
}
是因为主应用程序中的父实体(Car 实体)有多个 @OneToMany 关联,其中一些还具有嵌套关联。如果我遵循这种方法,我最终会得到多个@Transactional 方法,例如getCarByIdWithWheels、getCarByIdWithSeats、getCarByIdWithSeatsAndWheels 等。但我想要的是能够执行以下操作:
Car c = carService.getById(1);
carService.loadWheelsForCar(c);
carService.loadSeatsForCar(c);
我尝试了一些在网络上找到的东西,但我找到的每个解决方案都是“重新加载”“Car”实体。
【问题讨论】:
标签: java hibernate jpa spring-data-jpa spring-data