Попытка ленивой загрузки и возврата списка внутри аннотированного метода @transactional и получение ошибки без сеанса

#spring-boot #spring-data-jpa #lazy-loading

Вопрос:

это работает, но когда я пытаюсь удалить courses.size , я не получаю ошибки сеанса.

 @Transactional
public List<Course> initiateCourses(Long id) {
    Instructor instructor = instructorRepository.findById(2L).get();
    List<Course> courses = instructor.getCourses();
    courses.size();
    return courses;
}

 

Это работает, но похоже на халтуру.

также я нашел другой способ загрузки ленивых коллекций.

 @Repository
public interface InstructorRepository extends CrudRepository<Instructor, Long> {
    @Query("SELECT p FROM Instructor p LEFT JOIN FETCH p.courses WHERE p.id = ?1")
    Optional<Instructor> findByIdAndFetchCourseEagerly(Long id);
}
 

какой из них я должен использовать с точки зрения производительности? или есть лучший способ извлечения ленивых инициализированных объектов.

Комментарии:

1. использование второго подхода-лучший способ. Первый вызовет N 1 проблем с запросами.

Ответ №1:

Вы можете работать с @EntityGraph тем, чтобы указать, какие части иерархии объектов следует извлекать:

 @Repository
public interface InstructorRepository extends CrudRepository<Instructor, Long> {

    @EntityGraph(type = EntityGraphType.FETCH, attributePaths = {"courses"})
    Optional<Instructor> findById(Long id);
}
 

См.: EntityGraph (JPA весенних данных)

Комментарии:

1. спасибо, кэширование также работает в entitygraph?

Ответ №2:

Этот прокси-сервер не будет инициализирован до тех пор, пока вы не извлекете из него элемент или не вызовете size() метод. Есть несколько способов решить вашу проблему без «магии»:

  1. Явно вызовите Hibernate.init() и передайте в нем свой прокси-сервер коллекции, прежде чем возвращать его из метода.
  2. Используйте диаграмму сущностей, как предложил Питер Уолсер