Home > front end >  JpaObjectRetrievalFailureException when saving entity with one-to-many and client-assigned ids
JpaObjectRetrievalFailureException when saving entity with one-to-many and client-assigned ids

Time:10-26

In a simple Spring Boot Application, I'm facing with a JpaObjectRetrievalFailureException when I'm trying to save an entity with one-to-many association and client-assigned ids.

Please take a look on these entities and on this simple repository:

@Entity
@Table(name = "cart")
public class Cart {
    @Id
    @Column(name = "id")
    private UUID id;

    @Column(name = "name")
    private String name;

    @OneToMany
    @JoinColumn(name = "cart_id")
    private List<Item> items;

    // constructors, getters, setters, equals and hashCode ommitted
}

@Entity
@Table(name = "item")
public class Item {
    @Id
    @Column(name = "id")
    private UUID id;
    @Column(name = "name")
    private String name;

    // constructors, getters, setters, equals and hashCode ommitted
}

public interface CartRepository extends JpaRepository<Cart, UUID> {
}

I wrote this test:

@DataJpaTest
class CartRepositoryTest {

    @Autowired
    private CartRepository cartRepository;

    @Test
    void should_save_cart() {
        // GIVEN
        final var cart = new Cart(UUID.randomUUID(), "cart");
        final var item = new Item(UUID.randomUUID(), "item");
        cart.setItems(List.of(item));

        // WHEN
        final var saved = cartRepository.save(cart);

        // THEN
        final var fetched = cartRepository.findById(saved.id());
        assertThat(fetched).isPresent();
    }
}

When I run the test, call to cartRepository.save(cart) fails with:

Unable to find com.example.testjpaonetomany.domain.Item with id f5658508-f3d0-4d9b-a1f0-17b614753356; nested exception is javax.persistence.EntityNotFoundException: Unable to find com.example.testjpaonetomany.domain.Item with id f5658508-f3d0-4d9b-a1f0-17b614753356
org.springframework.orm.jpa.JpaObjectRetrievalFailureException: Unable to find com.example.testjpaonetomany.domain.Item with id f5658508-f3d0-4d9b-a1f0-17b614753356; nested exception is javax.persistence.EntityNotFoundException: Unable to find com.example.testjpaonetomany.domain.Item with id f5658508-f3d0-4d9b-a1f0-17b614753356
    at app//org.springframework.orm.jpa.EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(EntityManagerFactoryUtils.java:379)
    at app//org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:235)
    at app//org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:551)
    at app//org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at app//org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at app//org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:152)
    at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at app//org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:174)
    at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at app//org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97)
    at app//org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at app//org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:215)
    at app/jdk.proxy3/jdk.proxy3.$Proxy105.save(Unknown Source)
    at app//com.example.testjpaonetomany.repository.CartRepositoryTest.should_save_cart(CartRepositoryTest.java:28)

If I modify my entities by adding @GeneratedValue for ids, and in my test, I replace UUID.randomUUID() by null to delegate to Hibernate the ID generation, the test passes.

How to deal with client-generated ids?

CodePudding user response:

The cause is that you save the parent object only (which is absolutely correct and fine) but still need to explain JPA that the operation should be propagated i.e.

@OneToMany
@JoinColumn(name = "cart_id", cascade = CascadeType.ALL, orphanRemoval = true)
private List<Item> items;

As minor improvements I would suggest to put the UUID generation into constructors and establish the relation via the dedicated method i.e.

final var cart = new Cart("cart");
cart.addItem(new Item("item"));

and probably consider using em.persist() instead of repository.save() as it makes a select request first in case of using uuids as @Augusto mentioned

  • Related