HHH-2643 - Improve Session.refresh() Javdoc to clarify contract

Instead of writing it in the JavaDocs, it's much more appropriate to document this behavior in the User Guide

(cherry picked from commit 5629457aa8)

Conflicts:
	documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc
	documentation/src/test/java/org/hibernate/userguide/pc/PersistenceContextTest.java
This commit is contained in:
Vlad Mihalcea 2016-10-31 13:54:30 +02:00 committed by Gail Badner
parent 517877fb27
commit 7541a2d9e2
2 changed files with 56 additions and 2 deletions

View File

@ -262,6 +262,29 @@ However, please note that Hibernate has the capability to handle this automatica
See the discussion of non-identifier <<chapters/domain/basic_types.adoc#mapping-generated,generated attributes>>.
====
[[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]
----
====
====

View File

@ -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<Book> books = new ArrayList<>( );
public Long getId() {