Hibernate.org Community Documentation

- Prev
- Next

## Chapter 3. Persistence Contexts

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`. Persistent data has a state in relation to both a persistence context and the underlying database.

Entity states

- `new`, or `transient` - the entity has just been instantiated and is not associated with a persistence context. It has no persistent representation in the database and no identifier value has been assigned.

- `managed`, or `persistent` - the entity has an associated identifier and is associated with a persistence context.

- `detached` - the entity has an associated identifier, but is no longer associated with a persistence context (usually because the persistence context was closed or the instance was evicted from the context)

- `removed` - the entity has an associated identifier and is associated with a persistence context, however it is scheduled for removal from the database.

In Hibernate native APIs, the persistence context is defined as the `org.hibernate.Session`. In JPA, the persistence context is defined by `javax.persistence.EntityManager`. Much of the `org.hibernate.Session` and `javax.persistence.EntityManager` methods deal with moving entities between these states.

## 3.1. 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 3.1. Example of making an entity persistent

    DomesticCat fritz = new DomesticCat();
    fritz.setColor( Color.GINGER );
    fritz.setSex( 'M' );
    fritz.setName( "Fritz" );
    session.save( fritz );

    DomesticCat fritz = new DomesticCat();
    fritz.setColor( Color.GINGER );
    fritz.setSex( 'M' );
    fritz.setName( "Fritz" );
    entityManager.persist( fritz );

`org.hibernate.Session` also has a method named `persist` which follows the exact semantic defined in the JPA specification for the `persist` method. It is this method on `org.hibernate.Session` to which the Hibernate `javax.persistence.EntityManager` implementation delegates.

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 application-assigned (usually natural) key value has to be set on the instance before `save` or `persist` is called.

## 3.2. Deleting entities

Entities can also be deleted.

Example 3.2. Example of deleting an entity

    session.delete( fritz );

    entityManager.remove( fritz );

It is important to note that Hibernate itself can handle deleting detached state. JPA, however, disallows it. The implication here is that the entity instance passed to the `org.hibernate.Session` `delete` method can be either in managed or detached state, while the entity instance passed to `remove` on `javax.persistence.EntityManager` must be in managed state.

## 3.3. 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 3.3. Example of obtaining an entity reference without initializing its data

    Book book = new Book();
    book.setAuthor( session.byId( Author.class ).getReference( authorId ) );

    Book book = new Book();
    book.setAuthor( entityManager.getReference( Author.class, authorId ) );

The above works on the assumption that the entity is defined to allow lazy loading, generally through use of runtime proxies. For more information see ???. In both cases an exception will be thrown later if the given entity does not refer to actual database state if and when the application attempts to use the returned proxy in any way that requires access to its data.

## 3.4. Obtain an entity with its data initialized

It is also quite common to want to obtain an entity along with with its data, for display for example.

Example 3.4. Example of obtaining an entity reference with its data initialized

    session.byId( Author.class ).load( authorId );

    entityManager.find( Author.class, authorId );

In both cases null is returned if no matching database row was found.

## 3.5. Obtain an entity by natural-id

In addition to allowing to load by identifier, Hibernate allows applications to load by declared natural identifier.

Example 3.5. Example of simple natural-id access

    @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" );

Example 3.6. Example of natural-id access

    import java.lang.String;

    @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();

Just like we saw above, access entity data by natural id allows both the `load` and `getReference` forms, with the same semantics.

Accessing persistent data by identifier and by natural-id is consistent in the Hibernate API. Each defines the same 2 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.

In addition to those 2 methods, each also defines the method `with` accepting a `org.hibernate.LockOptions` argument. Locking is discussed in a separate chapter.

## 3.6. Refresh entity state

You can reload an entity instance and it's collections at any time.

Example 3.7. Example of refreshing entity state

    Cat cat = session.get( Cat.class, catId );
    ...
    session.refresh( cat );

    Cat cat = entityManager.find( Cat.class, catId );
    ...
    entityManager.refresh( cat );

One case where this is useful is when it is known that the database state has changed since the data was read. Refreshing allows the current database state to be pulled into the entity instance and the persistence context.

Another case where this might be useful is when database triggers are used to initialize some of the properties of the entity. Note that only the entity instance and its collections are refreshed unless you specify `REFRESH` as a cascade style of any associations. However, please note that Hibernate has the capability to handle this automatically through its notion of generated properties. See ??? for information.

## 3.7. 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 3.8. Example of modifying managed state

    Cat cat = session.get( Cat.class, catId );
    cat.setName( "Garfield" );
    session.flush(); // generally this is not explicitly needed

    Cat cat = entityManager.find( Cat.class, catId );
    cat.setName( "Garfield" );
    entityManager.flush(); // generally this is not explicitly needed

## 3.8. Working with detached data

Detachment is the process of working with data outside the scope of any persistence context. Data becomes detached in a number of ways. Once the persistence context is closed, all data that was associated with it becomes detached. Clearing the persistence context has the same effect. Evicting a particular entity from the persistence context makes it detached. And finally, serialization will make the deserialized form be detached (the original instance is still managed).

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.

### 3.8.1. 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.

## Important

JPA does not provide for this model. This is only available through Hibernate `org.hibernate.Session`.

Example 3.9. Example of reattaching a detached entity

    session.saveOrUpdate( someDetachedCat );

The method name `update` is a bit misleading here. It does not mean that an `SQL` `UPDATE` is immediately performed. It does, however, mean that an `SQL` `UPDATE` will be performed when the persistence context is flushed since Hibernate does not know its previous state against which to compare for changes. Unless the entity is mapped with `select-before-update`, in which case Hibernate will pull the current state from the database and see if an update is needed.

Provided the entity is detached, `update` and `saveOrUpdate` operate exactly the same.

### 3.8.2. 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 instance that is in managed state.

Example 3.10. Visualizing merge

    Object detached = ...;
    Object managed = entityManager.find( detached.getClass(), detached.getId() );
    managed.setXyz( detached.getXyz() );
    ...
    return managed;

That is not exactly what happens, but its a good visualization.

Example 3.11. Example of merging a detached entity

    Cat theManagedInstance = session.merge( someDetachedCat );

    Cat theManagedInstance = entityManager.merge( someDetachedCat );

## 3.9. Checking persistent state

An application can verify the state of entities and collections in relation to the persistence context.

Example 3.12. Examples of verifying managed state

    assert session.contains( cat );

    assert entityManager.contains( cat );

Example 3.13. Examples of verifying laziness

    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
    }

    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
    }

In JPA there is an alternative means to check laziness using the following `javax.persistence.PersistenceUtil` pattern. However, the `javax.persistence.PersistenceUnitUtil` is recommended where ever possible

Example 3.14. Alternative JPA means to verify laziness

    javax.persistence.PersistenceUtil jpaUtil = javax.persistence.Persistence.getPersistenceUtil();
    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
    }

## 3.10. Accessing Hibernate APIs from JPA

JPA defines an incredibly useful method to allow applications access to the APIs of the underlying provider.

Example 3.15. Usage of EntityManager.unwrap

    Session session = entityManager.unwrap( Session.class );
    SessionImplementor sessionImplementor = entityManager.unwrap( SessionImplementor.class );

- PrevChapter 2. Transactions and concurrency control
- Up
- Home
- NextChapter 4. Batch Processing