HHH-9998 - Continue documentation TLC - natural-id
This commit is contained in:
parent
9b9b806aac
commit
603a410fdc
|
@ -9,12 +9,151 @@
|
|||
version="5.0"
|
||||
xml:lang="en"
|
||||
xmlns="http://docbook.org/ns/docbook"
|
||||
>
|
||||
xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<title>Natural Ids</title>
|
||||
|
||||
<para>
|
||||
* simple
|
||||
* composite
|
||||
* caching
|
||||
* apis
|
||||
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).
|
||||
</para>
|
||||
|
||||
<section xml:id="naturalid-mapping">
|
||||
<title>Natural Id Mapping</title>
|
||||
|
||||
<para>
|
||||
Natural ids are defined in terms of one or more persistent attributes.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Natural id using single basic attribute</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/SimpleBasicNaturalIdMapping.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Natural id using single embedded attribute</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/SimpleCompositeNaturalIdMapping.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<example>
|
||||
<title>Natural id using multiple persistent attributes</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/NonSimpleNaturalIdMapping.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
</section>
|
||||
|
||||
<section xml:id="naturalid-api">
|
||||
<title>Natural Id API</title>
|
||||
|
||||
<para>
|
||||
As stated before, Hibernate provides an API for loading entities by natural id. This is represented by the
|
||||
<interfacename>org.hibernate.NaturalIdLoadAccess</interfacename> contract obtained via
|
||||
<methodname>Session#byNaturalId</methodname>. If the entity does not define a natural id, an exception
|
||||
will be thrown there.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Using NaturalIdLoadAccess</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/NaturalIdLoadAccessUsage.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
NaturalIdLoadAccess offers 2 distinct methods for obtaining the entity:
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<methodname>load</methodname> - obtains a reference to the entity, making sure
|
||||
that the entity state is initialized.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<methodname>getReference</methodname> - 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.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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 <citetitle>Hibernate User Guide</citetitle>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
We will discuss the last method available on NaturalIdLoadAccess
|
||||
(<methodname>setSynchronizationEnabled</methodname>) in <xref linkend="naturalid-mutability-caching"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Because the Company and PostalCarrier entities define "simple" natural ids, we also allow simplified
|
||||
access to load them based on the natural ids.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Using SimpleNaturalIdLoadAccess</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/SimpleNaturalIdLoadAccessUsage.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
Here we see the use of the <interfacename>org.hibernate.SimpleNaturalIdLoadAccess</interfacename>
|
||||
contract, obtained via <methodname>Session#bySimpleNaturalId</methodname>. SimpleNaturalIdLoadAccess is similar
|
||||
to NaturalIdLoadAccess except that it does not define the <methodname>using</methodname> 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 <methodname>load</methodname>
|
||||
and <methodname>getReference</methodname> 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.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section xml:id="naturalid-mutability-caching">
|
||||
<title>Natural Id - Mutability and Caching</title>
|
||||
<para>
|
||||
A natural id may be mutable or immutable. By default <literal>@NaturalId</literal> 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, <literal>@NaturalId(mutable=true)</literal>
|
||||
should be used instead.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Mutable natural id</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/MutableNaturalIdMapping.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
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 <methodname>load</methodname> or <methodname>getReference</methodname> method is executed. To
|
||||
be clear: this is only pertinent for mutable natural ids.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
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 <methodname>setSynchronizationEnabled(false)</methodname> (the default is true). This will force
|
||||
Hibernate to circumvent the checking of mutable natural ids.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Mutable natural id synchronization use-case</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/MutableNaturalIdSynchronization.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
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.
|
||||
</para>
|
||||
|
||||
<example>
|
||||
<title>Natural id caching</title>
|
||||
<programlisting role="JAVA"><xi:include href="extras/NaturalIdCaching.java" parse="text" /></programlisting>
|
||||
</example>
|
||||
|
||||
</section>
|
||||
</chapter>
|
|
@ -0,0 +1,8 @@
|
|||
@Entity
|
||||
public class Person {
|
||||
@Id
|
||||
private Integer id;
|
||||
@NaturalId(mutable=true)
|
||||
private String ssn;
|
||||
...
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
Session session = ...;
|
||||
|
||||
Person person = session.bySimpleNaturalId( Person.class )
|
||||
.load( "123-45-6789" );
|
||||
person.setSsn( "987-65-4321" );
|
||||
|
||||
...
|
||||
|
||||
// returns null!
|
||||
person = session.bySimpleNaturalId( Person.class )
|
||||
.setSynchronizationEnabled( false )
|
||||
.load( "987-65-4321" );
|
||||
|
||||
// returns correctly!
|
||||
person = session.bySimpleNaturalId( Person.class )
|
||||
.setSynchronizationEnabled( true )
|
||||
.load( "987-65-4321" );
|
|
@ -0,0 +1,9 @@
|
|||
@Entity
|
||||
@NaturalIdCache
|
||||
public class Company {
|
||||
@Id
|
||||
private Integer id;
|
||||
@NaturalId
|
||||
private String taxIdentifier;
|
||||
...
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
Session session = ...;
|
||||
|
||||
Company company = session.byNaturalId( Company.class )
|
||||
.using( "taxIdentifier", "abc-123-xyz" )
|
||||
.load();
|
||||
|
||||
PostalCarrier carrier = session.byNaturalId( PostalCarrier.class )
|
||||
.using( "postalCode", new PostalCode( ... ) )
|
||||
.load();
|
||||
|
||||
Department department = ...;
|
||||
Course course = session.byNaturalId( Course.class )
|
||||
.using( "department", department )
|
||||
.using( "code", "101" )
|
||||
.load();
|
|
@ -0,0 +1,11 @@
|
|||
@Entity
|
||||
public class Course {
|
||||
@Id
|
||||
private Integer id;
|
||||
@NaturalId
|
||||
@ManyToOne
|
||||
private Department department;
|
||||
@NaturalId
|
||||
private String code;
|
||||
...
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
@Entity
|
||||
public class Company {
|
||||
@Id
|
||||
private Integer id;
|
||||
@NaturalId
|
||||
private String taxIdentifier;
|
||||
...
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
@Entity
|
||||
public class PostalCarrier {
|
||||
@Id
|
||||
private Integer id;
|
||||
@NaturalId
|
||||
@Embedded
|
||||
private PostalCode postalCode;
|
||||
...
|
||||
|
||||
}
|
||||
|
||||
@Embeddable
|
||||
public class PostalCode {
|
||||
...
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
Session session = ...;
|
||||
|
||||
Company company = session.bySimpleNaturalId( Company.class )
|
||||
.load( "abc-123-xyz" );
|
||||
|
||||
PostalCarrier carrier = session.bySimpleNaturalId( PostalCarrier.class )
|
||||
.load( new PostalCode( ... ) );
|
|
@ -4,20 +4,23 @@ Status of the documentation overhaul (5.0 version)
|
|||
Overall the plan is to define 3 DocBook-based guides. The intention is for this document to serve
|
||||
as an outline of the work and a status of what still needs done.
|
||||
|
||||
NOTE : entries marked with <strike>strike-through</strike> indicate that the content is believed to be done; review
|
||||
would still be appreciated.
|
||||
|
||||
|
||||
User Guide
|
||||
==========
|
||||
|
||||
Covers reference topics targeting users.
|
||||
|
||||
* Prefix (done)
|
||||
* Architecture (done)
|
||||
* DomainModel (done)
|
||||
* Bootstrap (done)
|
||||
* PersistenceContext (done)
|
||||
* Database_Access (done)
|
||||
* Transactions (done)
|
||||
* JNDI (done)
|
||||
* <strike>Prefix</strike>
|
||||
* <strike>Architecture</strike>
|
||||
* <strike>DomainModel</strike>
|
||||
* <strike>Bootstrap</strike>
|
||||
* <strike>PersistenceContext</strike>
|
||||
* <strike>Database_Access</strike>
|
||||
* <strike>Transactions</strike>
|
||||
* <strike>JNDI</strike>
|
||||
* Locking (needs some work)
|
||||
* Fetching (needs some work)
|
||||
* Batching (needs lot of work - not started - open questions)
|
||||
|
@ -28,7 +31,7 @@ Covers reference topics targeting users.
|
|||
* Native_Queries (needs lots of work)
|
||||
* Multi_Tenancy (needs some work)
|
||||
* OSGi (right place for this?)
|
||||
* Envers
|
||||
* Envers (right place for this?)
|
||||
* Portability (needs some work)
|
||||
|
||||
|
||||
|
@ -39,15 +42,15 @@ Covers mapping domain model to database. Note that a lot of the "not started" c
|
|||
matter of pulling that content in and better organizing it.
|
||||
|
||||
|
||||
* Prefix (done)
|
||||
* Data_Categorizations (done)
|
||||
* Basic_Types (done)
|
||||
* Composition (done)
|
||||
* Collection (needs some work)
|
||||
* <strike>Prefix</strike>
|
||||
* <strike>Data_Categorizations</strike>
|
||||
* <strike>Basic_Types</strike>
|
||||
* <strike>Composition</strike>
|
||||
* <strike>Collection (needs some work)
|
||||
* Entity (needs some work)
|
||||
* Secondary_Tables (not started)
|
||||
* Identifiers (mostly done - needs "derived id" stuff documented)
|
||||
* Natural_Id (not started)
|
||||
* <strike>Natural_Id</strike>
|
||||
* Associations (not started)
|
||||
* Attribute_Access (not started)
|
||||
* Mapping_Overrides - AttributeOverrides/AssociationOverrides (not started)
|
||||
|
|
Loading…
Reference in New Issue