diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc index caab6b5ce7..bcbdff948e 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc @@ -262,6 +262,29 @@ However, please note that Hibernate has the capability to handle this automatica See the discussion of non-identifier <>. ==== +[[pc-refresh-gotchas]] +==== Refresh gotchas + +The `refresh` entity state transition is meant to overwrite the entity attributes according to the info currently contained in the associated database record. + +However, you have to be very careful when cascading the refresh action to any transient entity. + +For instance, consider the following example: + +[[pc-refresh-child-entity-jpa-example]] +.Refreshing entity state gotcha +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-refresh-child-entity-jpa-example] +---- +==== + +In the aforementioned example, an `EntityNotFoundException` is thrown because the `Book` entity is still in a transient state. +When the refresh action is cascaded from the `Person` entity, Hibernate will not be able to locate the `Book` entity in the database. + +For this reason, you should be very careful when mixing the refresh action with transient child entity objects. + [[pc-detach]] === Working with detached data @@ -442,4 +465,4 @@ To verify if an entity instance is currently attached to the running persistence ---- include::{sourcedir-caching}/FirstLevelCacheTest.java[tags=caching-management-contains-example] ---- -==== \ No newline at end of file +==== diff --git a/documentation/src/test/java/org/hibernate/userguide/pc/PersistenceContextTest.java b/documentation/src/test/java/org/hibernate/userguide/pc/PersistenceContextTest.java index d5a112bdd6..71ed74b7d8 100644 --- a/documentation/src/test/java/org/hibernate/userguide/pc/PersistenceContextTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/pc/PersistenceContextTest.java @@ -9,7 +9,9 @@ package org.hibernate.userguide.pc; import java.sql.Statement; import java.util.ArrayList; import java.util.List; +import javax.persistence.CascadeType; import javax.persistence.Entity; +import javax.persistence.EntityNotFoundException; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; @@ -28,6 +30,8 @@ import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.junit.Test; import static org.hibernate.userguide.util.TransactionUtil.doInJPA; +import org.jboss.logging.Logger; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -37,6 +41,8 @@ import static org.junit.Assert.assertTrue; */ public class PersistenceContextTest extends BaseEntityManagerFunctionalTestCase { + private static final Logger log = Logger.getLogger( PersistenceContextTest.class ); + @Override protected Class[] getAnnotatedClasses() { return new Class[] { @@ -172,6 +178,31 @@ public class PersistenceContextTest extends BaseEntityManagerFunctionalTestCase //end::pc-refresh-jpa-example[] } ); + try { + doInJPA( this::entityManagerFactory, entityManager -> { + Long personId = _personId; + + //tag::pc-refresh-child-entity-jpa-example[] + try { + Person person = entityManager.find( Person.class, personId ); + + Book book = new Book(); + book.setId( 100L ); + book.setTitle( "Hibernate User Guide" ); + book.setAuthor( person ); + person.getBooks().add( book ); + + entityManager.refresh( person ); + } + catch ( EntityNotFoundException expected ) { + log.info( "Beware when cascading the refresh associations to transient entities!" ); + } + //end::pc-refresh-child-entity-jpa-example[] + } ); + } + catch ( Exception expected ) { + } + doInJPA( this::entityManagerFactory, entityManager -> { Session session = entityManager.unwrap( Session.class ); Long personId = _personId; @@ -335,7 +366,7 @@ public class PersistenceContextTest extends BaseEntityManagerFunctionalTestCase private String name; - @OneToMany(mappedBy = "author") + @OneToMany(mappedBy = "author", cascade = CascadeType.ALL) private List books = new ArrayList<>( ); public Long getId() {