Рубрики
Без рубрики

@OneToMany отношения в спящем режиме и его опасности

Руководство по сохранению сущностей после изучения нескольких исключений. Помечено как hibernate, java, настойчивость, новички.

Недавно у меня возникли проблемы с сохранением объекта в режиме гибернации. Я хотел бы описать свое путешествие по хорошо известному примеру документирования микрофонов караоке-бара! Здесь у нас есть два микрофона (конечно, желтый к обязательному черному!) для нашего бара под названием Monster Karaoke. Сначала мы создаем микрофоны, затем панель и в конечном итоге сохраняем ее в соответствующем репозитории JPA.

Microphone blackMicrophone = Microphone.builder()
                .microphoneId(UUID.randomUUID())
                .color("black")
                .build();

Microphone yellowMicrophone = Microphone.builder()
                .microphoneId(UUID.randomUUID())
                .color("yellow")
                .build();

List microphoneList = Arrays.asList(blackMicrophone, yellowMicrophone);

KaraokeBar karaokeBar = KaraokeBar.builder()
                .barId(UUID.randomUUID())
                .name("Monster Karaoke")
                .microphoneList(microphoneList)
                .build();

karaokeBarRepository.save(karaokeBar);

Объект караоке-бара содержит список объектов микрофона , который помечен как Hibernate @OneToMany . Но при выполнении кода происходит следующее:

Request processing failed; 
nested exception is org.springframework.orm.jpa.JpaObjectRetrievalFailureException: 
Unable to find de.schmowser.radio.domain.Microphone with id fb133ab8-72ee-4bf4-ac5f-4701cb99e766;

Не удалось найти? Я вижу, что нам нужно каскадировать постоянство таким образом, чтобы наши великолепно раскрашенные микропроцессоры сохранялись, когда есть экземпляр караоке-бара. Но даже после добавления

@OneToMany(cascade = CascadeType.PERSIST)
private List microphoneList;

a javax.настойчивость. EntityNotFoundException убеждает нас в том, что микрофоны все еще не зафиксированы для сохранения. И только сейчас я вспоминаю, что мы знаем кого-то, кто отвечает за сохранение любых объектов в базах данных. Это EntityManager внутри @PersistenceContext . После его автоматического подключения и использования EntityManager.persist появляется следующее сообщение:

No EntityManager with actual transaction available for current thread - 
cannot reliably process 'persist' call

Да, мы должны аннотировать метод с помощью @Transactional , обозначая, что все транзакционные вопросы обрабатываются в фоновом режиме автоматически! Кроме того, мы должны сначала определить объект на стороне владельца (караоке-бар), затем установить его в наших экземплярах микрофона, а затем настроить список в karaokeBar. В противном случае возникает это исключение.

org.hibernate.TransientPropertyValueException: 
Not-null property references a transient value - 
transient instance must be saved before current operation : 
de.schmowser.radio.domain.Microphone.karaokeBar -> de.schmowser.radio.domain.KaraokeBar

Такое ощущение, что мы близки к тому, чтобы сообщить нашим клиентам, какие микрофоны предлагает наш бар. Любопытно, что без команды Repository.save компилируется следующий фрагмент кода…

List microphoneList = Arrays.asList(blackMicrophone, yellowMicrophone);

karaokeBar.setMicrophoneList(microphoneList);

entityManager.persist(karaokeBar);
entityManager.persist(blackMicrophone);
entityManager.persist(yellowMicrophone);

karaokeBarRepository.save(karaokeBar);

…в то время как с сохранением этого не происходит. Включение последней строки вознаграждает нас за java.lang. Исключение UnsupportedOperationException . Это на самом деле довольно трудно расшифровать. Так или иначе, Hibernate не любит ни нас, ни неизменяемые списки. Поэтому мы даем ему то, что он хочет: что-то модифицировать.

List microphoneList = new ArrayList<>();
microphoneList.add(blackMicrophone);
microphoneList.add(yellowMicrophone);

Гибернация милосердна и дает нам то, чего мы желаем!

Hibernate: insert into karaoke_bar (name, karaokebar_id) values (?, ?)
Hibernate: insert into microphone (color, karaokebar_id, microphone_id) values (?, ?, ?)
Hibernate: insert into microphone (color, karaokebar_id, microphone_id) values (?, ?, ?)

Это в любом случае близко к вашему опыту работы с гибернацией? Как вы справляетесь с этим штормом исключений – в целом и, возможно, более эффективно?

Оригинал: “https://dev.to/schmowser/onetomany-relations-in-hibernate-and-its-perils-1a41”