JPA - как сделать возвращаемый объект снова обычным POJO
@Override
public void run(String... args) throws Exception {
Person person = personService.getPerson(1L);
System.out.println(person);
Person person1 = new Person();
System.out.println(person1);
}
Где Person это стандартно проаннотированная model с @Entity, @Table, полями @Column и т.д. Одно из полей - коллекция с LAZY инициализацией. Так вот, в случае person1 - я получу в распечатке эту коллекцию null - никто не возмущается лейзи или нет эта коллекция. А в случае с person мы конечно же получим
org.hibernate.LazyInitializationException: failed to lazily initialize a collection
то есть , ну я плохо уже понимаю этот момент, за person еще "кто-то" следит, хотя это вроде как уже detached объект от persistence context.
Вопрос - что надо сделать с person, чтобы его sout дал просто null на коллекцию. И можете подсказать где вообще об этом можно подробно почитать
Сам сервис personService дергает метод у репозитория getPersonByIdWithoutFetch
@Repository
public interface PersonRepository extends JpaRepository<Person,Long> {
@Query("SELECT p FROM Person p JOIN FETCH p.roles r WHERE p.id =:personId")
Person getPersonByIdWithFetch(Long personId);
@Query("SELECT p FROM Person p WHERE p.id =:personId")
Person getPersonByIdWithoutFetch(Long personId);
}
Person entity
@Entity
@Table(name = "persons")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(name = "username")
private String username;
@Column(name = "password")
private String password;
@ManyToMany(cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}, fetch = FetchType.LAZY)
@JoinTable(name = "person_roles",
joinColumns = @JoinColumn(name = "person_id"),
inverseJoinColumns = @JoinColumn(name = "role_id")
)
private List<Role> roles = new ArrayList<>();
}
Ответы (2 шт):
В момент когда вы делаете System.out.println(person); происходит вызов person.toString() именно в этот момент запрашивается ваше Lazy поле. Но не может проинициализироваться и возникает ошибка LazyInitializationException
Чтоб этого избежать, можно пометить метод аннотацией @Transactional, или в параметрах конфигурации задать свойство hibernate.enable_lazy_load_no_trans = true.
Есть статья на эту тему здесь https://vladmihalcea.com/the-best-way-to-handle-the-lazyinitializationexception/
После выполнения Person person = personService.getPerson(1L); объект person автоматически помещается в кэш персистности и Hibernate следит за всеми объектами, которые в нем находятся. Для того, чтобы вывести объект из кэша персистности можно сделать em.detach(person); (при этом в БД не идут никакие update и пр.) и тогда person будет вне компетенций Hibernate. Содержимое кэша можете посмотреть с помощью класса-утилиты. Функцию showSessionCaсhe8( session, 1 ) нужно вызвать до и после detach. В консоль будет выводиться также информация и о коллекции roles объекта person.