diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/BytecodeEnhancement.adoc b/documentation/src/main/asciidoc/userguide/chapters/pc/BytecodeEnhancement.adoc index 438e38ddff..08b170a19e 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/BytecodeEnhancement.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/pc/BytecodeEnhancement.adoc @@ -142,3 +142,6 @@ Default behavior is to fail the build, but it can be set so that only a warning include::{sourcedir}/maven-example.pom[] ---- ==== + +:sourcedir: ../../../../../test/java/org/hibernate/userguide/pc + diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc index d255788384..378d54ac3b 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/pc/PersistenceContext.adoc @@ -1,6 +1,7 @@ [[pc]] == Persistence Contexts -:sourcedir: extras +:sourcedir: ../../../../../test/java/org/hibernate/userguide/pc +:sourcedir-caching: ../../../../../test/java/org/hibernate/userguide/caching Both the `org.hibernate.Session` API and `javax.persistence.EntityManager` API represent a context for dealing with persistent data. This concept is called a `persistence context`. @@ -15,35 +16,43 @@ It may or may not physically exist in the database yet. Much of the `org.hibernate.Session` and `javax.persistence.EntityManager` methods deal with moving entities between these states. +[[pc-unwrap]] === Accessing Hibernate APIs from JPA JPA defines an incredibly useful method to allow applications access to the APIs of the underlying provider. +[[pc-unwrap-example]] .Accessing Hibernate APIs from JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/UnwrapWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-unwrap-example] ---- ==== include::BytecodeEnhancement.adoc[] +[[pc-persist]] === Making entities persistent Once you've created a new entity instance (using the standard `new` operator) it is in `new` state. You can make it persistent by associating it to either a `org.hibernate.Session` or `javax.persistence.EntityManager`. -.Example of making an entity persistent +[[pc-persist-jpa-example]] +.Making an entity persistent with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/MakingPersistentWithSession.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-persist-jpa-example] ---- +==== -[source,java] +[[pc-persist-native-example]] +.Making an entity persistent with Hibernate API +==== +[source, JAVA, indent=0] ---- -include::{sourcedir}/MakingPersistentWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-persist-native-example] ---- ==== @@ -53,20 +62,26 @@ It is this `org.hibernate.Session` method to which the Hibernate `javax.persiste If the `DomesticCat` entity type has a generated identifier, the value is associated to the instance when the save or persist is called. If the identifier is not automatically generated, the manually assigned (usually natural) key value has to be set on the instance before the save or persist methods are called. -=== Deleting entities +[[pc-remove]] +=== Deleting (removing) entities Entities can also be deleted. -.Example of deleting an entity +[[pc-remove-jpa-example]] +.Deleting an entity with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/DeletingWithSession.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-remove-jpa-example] ---- +==== -[source,java] +[[pc-remove-native-example]] +.Deleting an entity with Hibernate API +==== +[source, JAVA, indent=0] ---- -include::{sourcedir}/DeletingWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-remove-native-example] ---- ==== @@ -78,90 +93,160 @@ The implication here is that the entity instance passed to the `org.hibernate.Se while the entity instance passed to remove on `javax.persistence.EntityManager` must be in managed state. ==== +[[pc-get-reference]] === Obtain an entity reference without initializing its data Sometimes referred to as lazy loading, the ability to obtain a reference to an entity without having to load its data is hugely important. The most common case being the need to create an association between an entity and another existing entity. -.Example of obtaining an entity reference without initializing its data +[[pc-get-reference-jpa-example]] +.Obtaining an entity reference without initializing its data with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/GetReferenceWithSession.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-get-reference-jpa-example] ---- +==== -[source,java] +[[pc-get-reference-native-example]] +.Obtaining an entity reference without initializing its data with Hibernate API +==== +[source, JAVA, indent=0] ---- -include::{sourcedir}/GetReferenceWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-get-reference-native-example] ---- ==== The above works on the assumption that the entity is defined to allow lazy loading, generally through use of runtime proxies. In both cases an exception will be thrown later if the given entity does not refer to actual database state when the application attempts to use the returned proxy in any way that requires access to its data. +[[pc-find]] === Obtain an entity with its data initialized It is also quite common to want to obtain an entity along with its data (e.g. like when we need to display it in the UI). -.Example of obtaining an entity reference with its data initialized +[[pc-find-jpa-example]] +.Obtaining an entity reference with its data initialized with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/LoadWithSession.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-find-jpa-example] ---- +==== -[source,java] +[[pc-find-native-example]] +.Obtaining an entity reference with its data initialized with Hibernate API +==== + +[source, JAVA, indent=0] ---- -include::{sourcedir}/LoadWithSession.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-find-native-example] +---- +==== + +[[pc-find-by-id-native-example]] +.Obtaining an entity reference with its data initialized using the `byId()` Hibernate API +==== + +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-find-by-id-native-example] ---- ==== In both cases null is returned if no matching database row was found. +[[pc-find-natural-id]] === Obtain an entity by natural-id In addition to allowing to load by identifier, Hibernate allows applications to load by declared natural identifier. -.Example of simple natural-id access +[[pc-find-by-natural-id-entity-example]] +.Natural-id mapping ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/SimpleNaturalIdLoading.java[] ----- - -[source,java] ----- -include::{sourcedir}/NaturalIdLoading.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-find-by-natural-id-entity-example] ---- ==== We can also opt to fetch the entity or just retrieve a reference to it when using the natural identifier loading methods. +[[pc-find-by-simple-natural-id-example]] +.Get entity reference by simple natural-id +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-find-by-simple-natural-id-example] +---- +==== + +[[pc-find-by-natural-id-example]] +.Load entity by natural-id +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-find-by-natural-id-example] +---- +==== + Hibernate offer a consistent API for accessing persistent data by identifier or by the natural-id. Each of these defines the same two data access methods: -getReference:: Should be used in cases where the identifier is assumed to exist, where non-existence would be an actual error. -Should never be used to test existence. -That is because this method will prefer to create and return a proxy if the data is not already associated with the Session rather than hit the database. -The quintessential use-case for using this method is to create foreign-key based associations. -load:: Will return the persistent data associated with the given identifier value or null if that identifier does not exist. +getReference:: + Should be used in cases where the identifier is assumed to exist, where non-existence would be an actual error. + Should never be used to test existence. + That is because this method will prefer to create and return a proxy if the data is not already associated with the Session rather than hit the database. + The quintessential use-case for using this method is to create foreign-key based associations. +load:: + Will return the persistent data associated with the given identifier value or null if that identifier does not exist. Each of these two methods define an overloading variant accepting a `org.hibernate.LockOptions` argument. Locking is discussed in a separate <>. +[[pc-managed-state]] +=== Modifying managed/persistent state + +Entities in managed/persistent state may be manipulated by the application and any changes will be automatically detected and persisted when the persistence context is flushed. +There is no need to call a particular method to make your modifications persistent. + +[[pc-managed-state-jpa-example]] +.Modifying managed state with JPA +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-managed-state-jpa-example] +---- +==== + +[[pc-managed-state-native-example]] +.Modifying managed state with Hibernate API +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-managed-state-native-example] +---- +==== + +[[pc-refresh]] === Refresh entity state You can reload an entity instance and its collections at any time. -.Example of refreshing entity state +[[pc-refresh-jpa-example]] +.Refreshing entity state with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/RefreshWithSession.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-refresh-jpa-example] ---- +==== -[source,java] +[[pc-refresh-native-example]] +.Refreshing entity state with Hibernate API +==== +[source, JAVA, indent=0] ---- -include::{sourcedir}/RefreshWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-refresh-native-example] ---- ==== @@ -177,24 +262,7 @@ However, please note that Hibernate has the capability to handle this automatica See the discussion of non-identifier <>. ==== -=== Modifying managed/persistent state - -Entities in managed/persistent state may be manipulated by the application and any changes will be automatically detected and persisted when the persistence context is flushed. -There is no need to call a particular method to make your modifications persistent. - -.Example of modifying managed state -==== -[source,java] ----- -include::{sourcedir}/ManagedUpdateWithSession.java[] ----- - -[source,java] ----- -include::{sourcedir}/ManagedUpdateWithEM.java[] ----- -==== - +[[pc-detach]] === Working with detached data Detachment is the process of working with data outside the scope of any persistence context. @@ -206,6 +274,7 @@ And finally, serialization will make the deserialized form be detached (the orig Detached data can still be manipulated, however the persistence context will no longer automatically know about these modification and the application will need to intervene to make the changes persistent again. +[[pc-detach-reattach]] ==== Reattaching detached data Reattachment is the process of taking an incoming entity instance that is in detached state and re-associating it with the current persistence context. @@ -215,16 +284,21 @@ Reattachment is the process of taking an incoming entity instance that is in det JPA does not provide for this model. This is only available through Hibernate `org.hibernate.Session`. ==== -.Example of reattaching a detached entity +[[pc-detach-reattach-lock-example]] +.Reattaching a detached entity using `lock` ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/ReattachingWithSession1.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-detach-reattach-lock-example] ---- +==== -[source,java] +[[pc-detach-reattach-saveOrUpdate-example]] +.Reattaching a detached entity using `saveOrUpdate` +==== +[source, JAVA, indent=0] ---- -include::{sourcedir}/ReattachingWithSession2.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-detach-reattach-saveOrUpdate-example] ---- ==== @@ -238,70 +312,89 @@ If the entity is mapped with `select-before-update`, Hibernate will pull the cur Provided the entity is detached, `update` and `saveOrUpdate` operate exactly the same. +[[pc-merge]] ==== Merging detached data Merging is the process of taking an incoming entity instance that is in detached state and copying its data over onto a new managed instance. Although not exactly per se, the following example is a good visualization of the `merge` operation internals. +[[pc-merge-visualize-example]] .Visualizing merge ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/VisualizingMerge.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-merge-visualize-example] ---- ==== -.Example of merging a detached entity +[[pc-merge-jpa-example]] +.Merging a detached entity with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/MergeWithSession.java[] ----- - -[source,java] ----- -include::{sourcedir}/MergeWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-merge-jpa-example] ---- ==== +[[pc-merge-native-example]] +.Merging a detached entity with Hibernate API +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-merge-native-example] +---- +==== + +[[pc-contains]] === Checking persistent state An application can verify the state of entities and collections in relation to the persistence context. -.Examples of verifying managed state +[[pc-contains-jpa-example]] +.Verifying managed state with JPA ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/ContainsWithSession.java[] ----- - -[source,java] ----- -include::{sourcedir}/ContainsWithEM.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-contains-jpa-example] ---- ==== -.Examples of verifying laziness +[[pc-contains-native-example]] +.Verifying managed state with Hibernate API ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/CheckingLazinessWithHibernate.java[] ----- - -[source,java] ----- -include::{sourcedir}/CheckingLazinessWithJPA.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-contains-native-example] ---- ==== -In JPA there is an alternative means to check laziness using the following `javax.persistence.PersistenceUtil` pattern (which is recommended where ever possible). +[[pc-verify-lazy-jpa-example]] +.Verifying laziness with JPA +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-verify-lazy-jpa-example] +---- +==== +[[pc-verify-lazy-native-example]] +.Verifying laziness with Hibernate API +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/PersistenceContextTest.java[tags=pc-verify-lazy-native-example] +---- +==== + +In JPA there is an alternative means to check laziness using the following `javax.persistence.PersistenceUtil` pattern (which is recommended wherever possible). + +[[pc-verify-lazy-jpa-alternative-example]] .Alternative JPA means to verify laziness ==== -[source,java] +[source, JAVA, indent=0] ---- -include::{sourcedir}/CheckingLazinessWithJPA2.java[] +include::{sourcedir}/PersistenceContextTest.java[tags=pc-verify-lazy-jpa-alternative-example] ---- ==== @@ -316,7 +409,7 @@ the `evict()` method can be used to remove the object and its collections from t ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/caching/FirstLevelCacheTest.java[tags=caching-management-jpa-detach-example] +include::{sourcedir-caching}/FirstLevelCacheTest.java[tags=caching-management-jpa-detach-example] ---- ==== @@ -325,7 +418,7 @@ include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/caching ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/caching/FirstLevelCacheTest.java[tags=caching-management-native-evict-example] +include::{sourcedir-caching}/FirstLevelCacheTest.java[tags=caching-management-native-evict-example] ---- ==== @@ -336,7 +429,7 @@ To detach all entities from the current persistence context, both the `EntityMan ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/caching/FirstLevelCacheTest.java[tags=caching-management-clear-example] +include::{sourcedir-caching}/FirstLevelCacheTest.java[tags=caching-management-clear-example] ---- ==== @@ -347,6 +440,6 @@ To verify if an entity instance is currently attached to the running persistence ==== [source, JAVA, indent=0] ---- -include::{sourcedir}/../../../../../../test/java/org/hibernate/userguide/caching/FirstLevelCacheTest.java[tags=caching-management-contains-example] +include::{sourcedir-caching}/FirstLevelCacheTest.java[tags=caching-management-contains-example] ---- ==== \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/CheckingLazinessWithHibernate.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/CheckingLazinessWithHibernate.java deleted file mode 100644 index de650d7718..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/CheckingLazinessWithHibernate.java +++ /dev/null @@ -1,9 +0,0 @@ -if( Hibernate.isInitialized(customer.getAddress() ){ - //display address if loaded -} -if( Hibernate.isInitialized(customer.getOrders() )) ){ - //display orders if loaded -} -if( Hibernate.isPropertyInitialized(customer,"detailedBio" ) ){ - //display property detailedBio if loaded -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/CheckingLazinessWithJPA.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/CheckingLazinessWithJPA.java deleted file mode 100644 index 39a47321cb..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/CheckingLazinessWithJPA.java +++ /dev/null @@ -1,10 +0,0 @@ -javax.persistence.PersistenceUnitUtil jpaUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil(); -if( jpaUtil.isLoaded(customer.getAddress() ){ - //display address if loaded -} -if( jpaUtil.isLoaded(customer.getOrders() )) ){ - //display orders if loaded -} -if( jpaUtil.isLoaded(customer,"detailedBio" ) ){ - //display property detailedBio if loaded -} \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ContainsWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ContainsWithEM.java deleted file mode 100644 index 12aaaff765..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ContainsWithEM.java +++ /dev/null @@ -1 +0,0 @@ -assert entityManager.contains( cat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ContainsWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ContainsWithSession.java deleted file mode 100644 index acb40fed3e..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ContainsWithSession.java +++ /dev/null @@ -1 +0,0 @@ -assert session.contains( cat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/DeletingWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/DeletingWithEM.java deleted file mode 100644 index 0938f5a3bf..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/DeletingWithEM.java +++ /dev/null @@ -1 +0,0 @@ -entityManager.remove( fritz ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/DeletingWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/DeletingWithSession.java deleted file mode 100644 index 25831ee346..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/DeletingWithSession.java +++ /dev/null @@ -1 +0,0 @@ -session.delete( fritz ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/GetReferenceWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/GetReferenceWithEM.java deleted file mode 100644 index acb668b0b7..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/GetReferenceWithEM.java +++ /dev/null @@ -1,2 +0,0 @@ -Book book = new Book(); -book.setAuthor( entityManager.getReference(Author.class,authorId ) ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/GetReferenceWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/GetReferenceWithSession.java deleted file mode 100644 index eb65dae49f..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/GetReferenceWithSession.java +++ /dev/null @@ -1,2 +0,0 @@ -Book book = new Book(); -book.setAuthor( session.byId(Author.class ).getReference( authorId ) ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/LoadWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/LoadWithEM.java deleted file mode 100644 index ee5cf293e2..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/LoadWithEM.java +++ /dev/null @@ -1 +0,0 @@ -entityManager.find( Author.class,authorId ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/LoadWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/LoadWithSession.java deleted file mode 100644 index d9801ef3e6..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/LoadWithSession.java +++ /dev/null @@ -1 +0,0 @@ -session.byId( Author.class ).load( authorId ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MakingPersistentWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MakingPersistentWithEM.java deleted file mode 100644 index e1b92d854e..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MakingPersistentWithEM.java +++ /dev/null @@ -1,7 +0,0 @@ -// Using the JPA EntityManager -DomesticCat fritz = new DomesticCat(); -fritz.setColor( Color.GINGER ); -fritz.setSex('M'); -fritz.setName( "Fritz" ); - -entityManager.persist( fritz ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MakingPersistentWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MakingPersistentWithSession.java deleted file mode 100644 index 4eea66c79b..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MakingPersistentWithSession.java +++ /dev/null @@ -1,7 +0,0 @@ -// Using the Hibernate Session -DomesticCat fritz = new DomesticCat(); -fritz.setColor( Color.GINGER ); -fritz.setSex('M'); -fritz.setName( "Fritz" ); - -session.save( fritz ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ManagedUpdateWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ManagedUpdateWithEM.java deleted file mode 100644 index ae3155f71d..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ManagedUpdateWithEM.java +++ /dev/null @@ -1,3 +0,0 @@ -Cat cat = entityManager.find( Cat.class,catId ); -cat.setName( "Garfield" ); -entityManager.flush(); // generally this is not explicitly needed \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ManagedUpdateWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ManagedUpdateWithSession.java deleted file mode 100644 index 337b4de9c3..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ManagedUpdateWithSession.java +++ /dev/null @@ -1,3 +0,0 @@ -Cat cat = session.get( Cat.class,catId ); -cat.setName( "Garfield" ); -session.flush(); // generally this is not explicitly needed \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MergeWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MergeWithEM.java deleted file mode 100644 index 340af5cddf..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MergeWithEM.java +++ /dev/null @@ -1 +0,0 @@ -Cat theManagedInstance = entityManager.merge( someDetachedCat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MergeWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MergeWithSession.java deleted file mode 100644 index adfad9d69e..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/MergeWithSession.java +++ /dev/null @@ -1 +0,0 @@ -Cat theManagedInstance = session.merge( someDetachedCat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/NaturalIdLoading.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/NaturalIdLoading.java deleted file mode 100644 index c64b38b04f..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/NaturalIdLoading.java +++ /dev/null @@ -1,30 +0,0 @@ -@Entity -public class User { - - @Id - @GeneratedValue - Long id; - - @NaturalId - String system; - - @NaturalId - String userName; - - ... -} - -// use getReference() to create associations... -Resource aResource = ( Resource ) session.byId( Resource.class ).getReference( 123 ); -User aUser = ( User ) session.byNaturalId( User.class ) - .using( "system", "prod" ) - .using( "userName", "steve" ) - .getReference(); - -aResource.assignTo( user ); - -// use load() to pull initialzed data -return session.byNaturalId( User.class ) - .using( "system","prod" ) - .using( "userName","steve" ) - .load(); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ReattachingWithSession1.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ReattachingWithSession1.java deleted file mode 100644 index 7a77282116..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ReattachingWithSession1.java +++ /dev/null @@ -1 +0,0 @@ -session.lock( someDetachedCat,LockMode.NONE ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ReattachingWithSession2.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ReattachingWithSession2.java deleted file mode 100644 index a26c2c98b0..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/ReattachingWithSession2.java +++ /dev/null @@ -1 +0,0 @@ -session.saveOrUpdate( someDetachedCat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/RefreshWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/RefreshWithEM.java deleted file mode 100644 index 8258af31e6..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/RefreshWithEM.java +++ /dev/null @@ -1,3 +0,0 @@ -Cat cat = entityManager.find( Cat.class, catId ); -... -entityManager.refresh( cat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/RefreshWithSession.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/RefreshWithSession.java deleted file mode 100644 index 3436fe3f88..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/RefreshWithSession.java +++ /dev/null @@ -1,3 +0,0 @@ -Cat cat = session.get( Cat.class, catId ); -... -session.refresh( cat ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/SimpleNaturalIdLoading.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/SimpleNaturalIdLoading.java deleted file mode 100644 index 4706a88052..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/SimpleNaturalIdLoading.java +++ /dev/null @@ -1,22 +0,0 @@ -@Entity -public class User { - - @Id - @GeneratedValue - Long id; - - @NaturalId - String userName; - - ... -} - -// use getReference() to create associations... -Resource aResource = ( Resource ) session.byId( Resource.class ).getReference( 123 ); -User aUser = ( User ) session.bySimpleNaturalId( User.class ).getReference( "steve" ); - -aResource.assignTo( user ); - - -// use load() to pull initialzed data -return session.bySimpleNaturalId( User.class ).load( "steve" ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/UnwrapWithEM.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/UnwrapWithEM.java deleted file mode 100644 index d0c4fac2aa..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/UnwrapWithEM.java +++ /dev/null @@ -1,2 +0,0 @@ -Session session = entityManager.unwrap( Session.class ); -SessionImplementor sessionImplementor = entityManager.unwrap( SessionImplementor.class ); \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/VisualizingMerge.java b/documentation/src/main/asciidoc/userguide/chapters/pc/extras/VisualizingMerge.java deleted file mode 100644 index 3f8697a4ae..0000000000 --- a/documentation/src/main/asciidoc/userguide/chapters/pc/extras/VisualizingMerge.java +++ /dev/null @@ -1,5 +0,0 @@ -Object detached = ...; -Object managed = entityManager.find( detached.getClass(), detached.getId() ); -managed.setXyz( detached.getXyz() ); -... -return managed; \ 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 new file mode 100644 index 0000000000..e8429f4e7a --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/pc/PersistenceContextTest.java @@ -0,0 +1,412 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.userguide.pc; + +import java.sql.Statement; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Persistence; +import javax.persistence.PersistenceUnitUtil; +import javax.persistence.PersistenceUtil; + +import org.hibernate.Hibernate; +import org.hibernate.LockMode; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.annotations.NaturalId; +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.userguide.util.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * @author Vlad Mihalcea + */ +public class PersistenceContextTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + Book.class, + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::pc-unwrap-example[] + Session session = entityManager.unwrap( Session.class ); + SessionImplementor sessionImplementor = entityManager.unwrap( SessionImplementor.class ); + + SessionFactory sessionFactory = entityManager.getEntityManagerFactory().unwrap( SessionFactory.class ); + //end::pc-unwrap-example[] + } ); + Long _personId = doInJPA( this::entityManagerFactory, entityManager -> { + entityManager.createQuery( "delete from Book" ).executeUpdate(); + entityManager.createQuery( "delete from Person" ).executeUpdate(); + + //tag::pc-persist-jpa-example[] + Person person = new Person(); + person.setId( 1L ); + person.setName("John Doe"); + + entityManager.persist( person ); + //end::pc-persist-jpa-example[] + + //tag::pc-remove-jpa-example[] + entityManager.remove( person ); + //end::pc-remove-jpa-example[] + + entityManager.persist( person ); + Long personId = person.getId(); + + //tag::pc-get-reference-jpa-example[] + Book book = new Book(); + book.setAuthor( entityManager.getReference( Person.class, personId ) ); + //end::pc-get-reference-jpa-example[] + + return personId; + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Long personId = _personId; + + //tag::pc-find-jpa-example[] + Person person = entityManager.find( Person.class, personId ); + //end::pc-find-jpa-example[] + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + entityManager.createQuery( "delete from Book" ).executeUpdate(); + entityManager.createQuery( "delete from Person" ).executeUpdate(); + + //tag::pc-persist-native-example[] + Person person = new Person(); + person.setId( 1L ); + person.setName("John Doe"); + + session.save( person ); + //end::pc-persist-native-example[] + + //tag::pc-remove-native-example[] + session.delete( person ); + //end::pc-remove-native-example[] + + session.save( person ); + Long personId = person.getId(); + + //tag::pc-get-reference-native-example[] + Book book = new Book(); + book.setId( 1L ); + book.setIsbn( "123-456-7890" ); + entityManager.persist( book ); + book.setAuthor( session.load( Person.class, personId ) ); + //end::pc-get-reference-native-example[] + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-find-native-example[] + Person person = session.get( Person.class, personId ); + //end::pc-find-native-example[] + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-find-by-id-native-example[] + Person person = session.byId( Person.class ).load( personId ); + //end::pc-find-by-id-native-example[] + + String isbn = "123-456-7890"; + + //tag::pc-find-by-simple-natural-id-example[] + Book book = session.bySimpleNaturalId( Book.class ).getReference( isbn ); + //end::pc-find-by-simple-natural-id-example[] + assertNotNull(book); + } ); + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + String isbn = "123-456-7890"; + + //tag::pc-find-by-natural-id-example[] + Book book = session.byNaturalId( Book.class ).using( "isbn", isbn ).load( ); + //end::pc-find-by-natural-id-example[] + assertNotNull(book); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Long personId = _personId; + + //tag::pc-managed-state-jpa-example[] + Person person = entityManager.find( Person.class, personId ); + person.setName("John Doe"); + entityManager.flush(); + //end::pc-managed-state-jpa-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Long personId = _personId; + + //tag::pc-refresh-jpa-example[] + Person person = entityManager.find( Person.class, personId ); + + entityManager.createQuery( "update Person set name = UPPER(name)" ).executeUpdate(); + + entityManager.refresh( person ); + assertEquals("JOHN DOE", person.getName() ); + //end::pc-refresh-jpa-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-managed-state-native-example[] + Person person = session.byId( Person.class ).load( personId ); + person.setName("John Doe"); + entityManager.flush(); + //end::pc-managed-state-native-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-refresh-native-example[] + Person person = session.byId( Person.class ).load( personId ); + + session.doWork( connection -> { + try(Statement statement = connection.createStatement()) { + statement.executeUpdate( "UPDATE person SET name = UPPER(name)" ); + } + } ); + + session.refresh( person ); + assertEquals("JOHN DOE", person.getName() ); + //end::pc-refresh-native-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-detach-reattach-lock-example[] + Person person = session.byId( Person.class ).load( personId ); + //Clear the Session so the person entity becomes detached + session.clear(); + person.setName( "Mr. John Doe" ); + + session.lock( person, LockMode.NONE ); + //end::pc-detach-reattach-lock-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-detach-reattach-saveOrUpdate-example[] + Person person = session.byId( Person.class ).load( personId ); + //Clear the Session so the person entity becomes detached + session.clear(); + person.setName( "Mr. John Doe" ); + + session.saveOrUpdate( person ); + //end::pc-detach-reattach-saveOrUpdate-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + Person personDetachedReference = session.byId( Person.class ).load( personId ); + //Clear the Session so the person entity becomes detached + session.clear(); + new MergeVisualizer( session ).merge( personDetachedReference ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Long personId = _personId; + + //tag::pc-merge-jpa-example[] + Person person = entityManager.find( Person.class, personId ); + //Clear the EntityManager so the person entity becomes detached + entityManager.clear(); + person.setName( "Mr. John Doe" ); + + person = entityManager.merge( person ); + //end::pc-merge-jpa-example[] + + //tag::pc-contains-jpa-example[] + boolean contained = entityManager.contains( person ); + //end::pc-contains-jpa-example[] + assertTrue( contained ); + + //tag::pc-verify-lazy-jpa-example[] + PersistenceUnitUtil persistenceUnitUtil = entityManager.getEntityManagerFactory().getPersistenceUnitUtil(); + + boolean personInitialized = persistenceUnitUtil.isLoaded( person ); + + boolean personBooksInitialized = persistenceUnitUtil.isLoaded( person.getBooks() ); + + boolean personNameInitialized = persistenceUnitUtil.isLoaded( person, "name" ); + //end::pc-verify-lazy-jpa-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Long personId = _personId; + + Person person = entityManager.find( Person.class, personId ); + + //tag::pc-verify-lazy-jpa-alternative-example[] + PersistenceUtil persistenceUnitUtil = Persistence.getPersistenceUtil(); + + boolean personInitialized = persistenceUnitUtil.isLoaded( person ); + + boolean personBooksInitialized = persistenceUnitUtil.isLoaded( person.getBooks() ); + + boolean personNameInitialized = persistenceUnitUtil.isLoaded( person, "name" ); + //end::pc-verify-lazy-jpa-alternative-example[] + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + Session session = entityManager.unwrap( Session.class ); + Long personId = _personId; + + //tag::pc-merge-native-example[] + Person person = session.byId( Person.class ).load( personId ); + //Clear the Session so the person entity becomes detached + session.clear(); + person.setName( "Mr. John Doe" ); + + person = (Person) session.merge( person ); + //end::pc-merge-native-example[] + + //tag::pc-contains-native-example[] + boolean contained = session.contains( person ); + //end::pc-contains-native-example[] + assertTrue( contained ); + + //tag::pc-verify-lazy-native-example[] + boolean personInitialized = Hibernate.isInitialized( person ); + + boolean personBooksInitialized = Hibernate.isInitialized( person.getBooks() ); + + boolean personNameInitialized = Hibernate.isPropertyInitialized( person, "name" ); + //end::pc-verify-lazy-native-example[] + } ); + } + + public static class MergeVisualizer { + private final Session session; + + public MergeVisualizer(Session session) { + this.session = session; + } + + //tag::pc-merge-visualize-example[] + public Person merge(Person detached) { + Person newReference = session.byId( Person.class ).load( detached.getId() ); + newReference.setName( detached.getName() ); + return newReference; + } + //end::pc-merge-visualize-example[] + } + + + + @Entity(name = "Person") + public static class Person { + + @Id + private Long id; + + private String name; + + @OneToMany(mappedBy = "author") + private List books = new ArrayList<>( ); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getBooks() { + return books; + } + } + + //tag::pc-find-by-natural-id-entity-example[] + @Entity(name = "Book") + public static class Book { + + @Id + private Long id; + + private String title; + + @NaturalId + private String isbn; + + @ManyToOne + private Person author; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public Person getAuthor() { + return author; + } + + public void setAuthor(Person author) { + this.author = author; + } + + public String getIsbn() { + return isbn; + } + + public void setIsbn(String isbn) { + this.isbn = isbn; + } + } + //end::pc-find-by-natural-id-entity-example[] +}