Hibernate.orgCommunity Documentation

Chapter 7. Natural Ids

Table of Contents

7.1. Natural Id Mapping
7.2. Natural Id API
7.3. Natural Id - Mutability and Caching

Natural ids represent unique identifiers that naturally exist within your domain model. Even if a natural id does not make a good primary key, it still is useful to tell Hibernate about it. As we will see later, Hibernate provides a dedicated, efficient API for loading and entity by its natural-id much like it offers for loading by identifier (PK).

Natural ids are defined in terms of one or more persistent attributes.

As stated before, Hibernate provides an API for loading entities by natural id. This is represented by the org.hibernate.NaturalIdLoadAccess contract obtained via Session#byNaturalId. If the entity does not define a natural id, an exception will be thrown there.

NaturalIdLoadAccess offers 2 distinct methods for obtaining the entity:

  • load - obtains a reference to the entity, making sure that the entity state is initialized.

  • getReference - obtains a reference to the entity. The state may or may not be initialized. If the entity is associated with the Session already, that reference (loaded or not) is returned; else if the entity supports proxy generation, an uninitialized proxy is generated and returned; otherwise the entity is loaded from the database and returned.

NaturalIdLoadAccess also allows to request locking for the load. We might use that to load an entity by natural id and at the same time apply a pessimistic lock. For additional details on locking, see the Hibernate User Guide.

We will discuss the last method available on NaturalIdLoadAccess (setSynchronizationEnabled) in Section 7.3, “Natural Id - Mutability and Caching”.

Because the Company and PostalCarrier entities define "simple" natural ids, we also allow simplified access to load them based on the natural ids.

Here we see the use of the org.hibernate.SimpleNaturalIdLoadAccess contract, obtained via Session#bySimpleNaturalId. SimpleNaturalIdLoadAccess is similar to NaturalIdLoadAccess except that it does not define the using method. Instead, because these "simple" natural ids are defined based on just one attribute we can directly pass the corresponding value of that natural id attribute directly to the load and getReference methods. If the entity does not define a natural id or if the natural id it does define is not simple, an exception will be thrown there.

A natural id may be mutable or immutable. By default @NaturalId marks an immutable natural id. An immutable natural id is expected to never change values. If the values of the natural id attribute(s) can change, @NaturalId(mutable=true) should be used instead.

Within the Session, Hibernate maintains a mapping from natural id values to pk values. If natural ids values have changed it is possible for this mapping to become out of date until a flush occurs. To work around this condition, Hibernate will attempt to discover any such pending changes and adjust for them when the load or getReference method is executed. To be clear: this is only pertinent for mutable natural ids.

This "discovery and adjustment" have a performance impact. If an application is certain that none of its mutable natural ids already associated with the Session have changed, it can disable that checking by calling setSynchronizationEnabled(false) (the default is true). This will force Hibernate to circumvent the checking of mutable natural ids.

Not only can this NaturalId-to-PK resolution be cached in the Session, but we can also have it cached in the second-level cache if second level caching is enabled.