Невозможно обновить вложенную сущность с помощью Hibernate JPA - PullRequest
0 голосов
/ 14 февраля 2020

Я использую Hibernate JPA и пытаюсь обновить вложенную сущность.

Сущности:

@Entity
@Table(name = "profile")
@AllArgsConstructor
@NoArgsConstructor
public class ProfileEntity implements Serializable {

........

    @OneToOne(cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    @JoinColumn(name="office_address")
    private AddressEntity officeAddress;
}

@Entity
@Table(name="address")
@AllArgsConstructor
@NoArgsConstructor
public class AddressEntity implements Serializable{

......

    @OneToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="user_id")
    private ProfileEntity userProfile;
}

Обновление сущности профиля с помощью новой сущности адреса

@Transactional
@Modifying
@Query("update ProfileEntity set officeAddress=:address where userId=:userId")
int updateProfile(
        @Param("userId") Long userId,
        @Param("address") AddressEntity address);

Ошибка :

org.springframework.dao.InvalidDataAccessApiUsageException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.example.entities.AddressEntity; nested exception is java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.example.entities.AddressEntity
    at org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:381)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:227)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:436)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:59)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:213)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:147)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
    .
    .
    .
    .

Я понимаю, что транзакция не фиксируется после вставки нового AddressEntity, а hibernate сбрасывается перед фиксацией. Таким образом, он не может выполнить обновление ProfileEntity с новым адресом PK.

Но как это исправить?

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

1 Ответ

1 голос
/ 14 февраля 2020

Полагаю, address вы пропустите, нет в базе данных. CascadeType.ALL не работает из-за обновления @Query. Каскадирование предоставляется только для операций PERSIST, MERGE, REMOVE, REFRESH, DETACH.

Используйте следующие

@Transactional
public ProfileEntity updateProfile(Long userId, AddressEntity address) {
    ProfileEntity profileEntity = profileEntityRepository.findByUserId(userId);

    profileEntity.setOfficeAddress(address);
    address.setUserProfile(profileEntity);

    return profileEntityRepository.save(profileEntity);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...