Рассмотрим следующее:
@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
и добавить результат в коллекцию. Я, вероятно, могу сделать это вручную, но это единственный способ go?
Я знаю, что LazyInitializationException
выдается, когда нет активного сеанса (не @Transactional
вызывает создание новенький?). Я пытался:
@Transactional
public void loadWheelsForCar(Car c) {
c.getWheels().size(); // will load wheels
}
, но возникло исключение.
В случае проблемы XY , причина, по которой я этого не делаю (CarService
):
@Transactional
public Optional<Car> getByIdWithWheels(int carId) {
Optional<Car> possibleCar = carRepository.findById(carId);
possibleCar.ifPresent(c -> c.getWheels().size());
return possibleCar;
}
потому что родительский объект (Car
entity) в основном приложении имеет несколько ассоциаций @OneToMany
, а некоторые из них также имеют вложенные. Если я буду следовать этому подходу, у меня будет несколько методов @Transactional
, таких как getCarByIdWithWheels
, getCarByIdWithSeats
, getCarByIdWithSeatsAndWheels
и т.д. c. Но я хочу иметь возможность делать что-то вроде:
Car c = carService.getById(1);
carService.loadWheelsForCar(c);
carService.loadSeatsForCar(c);
Я пробовал кое-что, найденное в сети, но каждое решение, которое я нашел, было «повторной загрузкой» объекта «Car
».