HHH-10022 - Continue documentation TLC (part 2)
This commit is contained in:
parent
bd6bb7b841
commit
8dc14436af
|
@ -23,13 +23,31 @@
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Identifiers model the primary key of an entity. They are used to uniquely identify each specific entity.
|
Identifiers model the primary key of an entity. They are used to uniquely identify each specific entity.
|
||||||
JPA defines the behavior of changing the value of the identifier attribute to be undefined; Hibernate simply
|
|
||||||
does not support that.
|
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Every entity must define an identifier. For entity inheritance hierarchies, the identifier must be
|
Hibernate and JPA both make the following assumptions about the corresponding database column(s):
|
||||||
defined just on the entity that is the root of the hierarchy.
|
<itemizedlist>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>UNIQUE</literal> - The values must uniquely identify each row.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>NOT NULL</literal> - The values cannot be null. For composite ids, no part can be null.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
<literal>IMMUTABLE</literal> - The values, once inserted, can never be changed. This is more
|
||||||
|
a general guide, than a hard-fast rule as opinions vary. JPA defines the behavior of changing the
|
||||||
|
value of the identifier attribute to be undefined; Hibernate simply does not support that. In cases
|
||||||
|
where the values for the PK you have chosen will be updated, Hibernate recommends mapping the
|
||||||
|
mutable value as a natural id, and use a surrogate id for the PK. See <xref linkend="naturalid"/>.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<note>
|
<note>
|
||||||
|
@ -41,10 +59,13 @@
|
||||||
</note>
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
An identifier might be simple (single value) or composite (multiple values).
|
Every entity must define an identifier. For entity inheritance hierarchies, the identifier must be
|
||||||
|
defined just on the entity that is the root of the hierarchy.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<!-- todo : be sure to discuss generators in simple, then reference from composite -->
|
<para>
|
||||||
|
An identifier might be simple (single value) or composite (multiple values).
|
||||||
|
</para>
|
||||||
|
|
||||||
<section xml:id="identifiers-simple">
|
<section xml:id="identifiers-simple">
|
||||||
<title>Simple identifiers</title>
|
<title>Simple identifiers</title>
|
||||||
|
@ -108,23 +129,8 @@
|
||||||
<title>Composite identifiers</title>
|
<title>Composite identifiers</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Composite identifiers correspond to one or more persistent attributes. A primary key class must be
|
Composite identifiers correspond to one or more persistent attributes. Here are the rules governing
|
||||||
defined to represent a composite primary key. Composite primary keys typically arise when mapping from
|
composite identifiers, as defined by the JPA specification.
|
||||||
legacy databases when the database key is comprised of several columns. The EmbeddedId
|
|
||||||
or IdClass annotation is used to denote a composite primary key. See Sections 11.1.17 and
|
|
||||||
11.1.22.
|
|
||||||
</para>
|
|
||||||
|
|
||||||
<note>
|
|
||||||
<para>
|
|
||||||
The restriction that a composite identifier has to be represented by a "primary key class" is
|
|
||||||
a JPA restriction. Hibernate does allow composite identifiers to be defined without a
|
|
||||||
"primary key class", but use of that modeling technique is deprecated and not discussed here.
|
|
||||||
</para>
|
|
||||||
</note>
|
|
||||||
|
|
||||||
<para>
|
|
||||||
Here are the rules governing composite identifiers, as defined by the JPA specification.
|
|
||||||
<itemizedlist>
|
<itemizedlist>
|
||||||
<listitem>
|
<listitem>
|
||||||
<para>
|
<para>
|
||||||
|
@ -154,20 +160,93 @@
|
||||||
</itemizedlist>
|
</itemizedlist>
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
The restriction that a composite identifier has to be represented by a "primary key class" is
|
||||||
|
a JPA restriction. Hibernate does allow composite identifiers to be defined without a
|
||||||
|
"primary key class", but use of that modeling technique is deprecated and not discussed here.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The attributes making up the composition can be either basic, composite, ManyToOne. Note especially
|
||||||
|
that collections and one-to-ones are never appropriate.
|
||||||
|
<!-- todo : discuss why a real one-to-one is never appropriate? -->
|
||||||
|
</para>
|
||||||
|
|
||||||
<section xml:id="identifiers-composite-aggregated">
|
<section xml:id="identifiers-composite-aggregated">
|
||||||
<title>Composite identifiers - aggregated (EmbeddedId)</title>
|
<title>Composite identifiers - aggregated (EmbeddedId)</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<!-- todo : write -->
|
Modelling a composite identifier using an EmbeddedId simply means defining an
|
||||||
blah blah blah
|
Embeddable to be a composition for the the one or more attributes making up the
|
||||||
|
identifier and then exposing an attribute of that Embeddable type on the entity.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Basic EmbeddedId</title>
|
||||||
|
<programlisting role="JAVA"><xi:include href="extras/EmbeddedId1.java" parse="text" /></programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
As mentioned before, EmbeddedIds can even contain ManyToOne attributes.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>EmbeddedId with ManyToOne</title>
|
||||||
|
<programlisting role="JAVA"><xi:include href="extras/EmbeddedId2.java" parse="text" /></programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
Hibernate supports directly modeling the ManyToOne in the PK class, whether EmbeddedId or IdClass.
|
||||||
|
However that is not portably supported by the JPA specification. In JPA terms one would
|
||||||
|
use "derived identifiers"; for details, see <xref linkend="identifiers-derived"/>.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section xml:id="identifiers-composite-nonaggregated">
|
<section xml:id="identifiers-composite-nonaggregated">
|
||||||
<title>Composite identifiers - non-aggregated (IdClass)</title>
|
<title>Composite identifiers - non-aggregated (IdClass)</title>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
<!-- todo : write -->
|
Modelling a composite identifier using an IdClass differs from using an EmbeddedId in that the entity
|
||||||
blah blah blah
|
defines each individual attribute making up the composition. The IdClass simply acts as a "shadow".
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>Basic IdClass</title>
|
||||||
|
<programlisting role="JAVA"><xi:include href="extras/IdClass1.java" parse="text" /></programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Non-aggregated composite identifiers can also contain ManyToOne attributes as we saw with aggregated
|
||||||
|
ones (still non-portably)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>IdClass with ManyToOne</title>
|
||||||
|
<programlisting role="JAVA"><xi:include href="extras/IdClass2.java" parse="text" /></programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
With non-aggregated composite identifiers, Hibernate also supports "partial" generation of the
|
||||||
|
composite values.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<example>
|
||||||
|
<title>IdClass with partial generation</title>
|
||||||
|
<programlisting role="JAVA"><xi:include href="extras/IdClass3.java" parse="text" /></programlisting>
|
||||||
|
</example>
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
This feature exists because of a highly questionable interpretation of the JPA specification
|
||||||
|
made by the SpecJ committee. Hibernate does not feel that JPA defines support for this, but
|
||||||
|
added the feature simply to be usable in SpecJ benchmarks. Use of this feature may or may not
|
||||||
|
be portable from a JPA perspective.
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
</section>
|
</section>
|
||||||
|
@ -175,6 +254,14 @@
|
||||||
<section xml:id="identifiers-generators">
|
<section xml:id="identifiers-generators">
|
||||||
<title>Generated identifier values</title>
|
<title>Generated identifier values</title>
|
||||||
|
|
||||||
|
<!-- todo : discuss select generator -->
|
||||||
|
|
||||||
|
<note>
|
||||||
|
<para>
|
||||||
|
For discussion of generated values for non-identifier attributes, see <xref linkend="generated"/>
|
||||||
|
</para>
|
||||||
|
</note>
|
||||||
|
|
||||||
<para>
|
<para>
|
||||||
Hibernate supports identifier value generation across a number of different types. Remember
|
Hibernate supports identifier value generation across a number of different types. Remember
|
||||||
that JPA portably defines identifier value generation just for integer types.
|
that JPA portably defines identifier value generation just for integer types.
|
||||||
|
@ -431,9 +518,75 @@
|
||||||
</para>
|
</para>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<para>
|
<section xml:id="identifiers-generators-optimizer">
|
||||||
For discussion of generated values for non-identifier attributes, see <xref linkend="generated"/>
|
<title>Optimizers</title>
|
||||||
</para>
|
|
||||||
|
<para>
|
||||||
|
Most of the Hibernate generators that separately obtain identifier values from database structures
|
||||||
|
support the use of pluggable optimizers. Optimizers help manage the number of times Hibernate
|
||||||
|
has to talk to the database in order to generate identifier values. For example, with no optimizer
|
||||||
|
applied to a sequence-generator, everytime the application asked Hibernate to generate an identifier
|
||||||
|
it would need to grab the next sequence value from the database. But if we can minimize the
|
||||||
|
number of times we need to communicate with the database here, the application will be able to perform
|
||||||
|
better. Which is in fact the role of these optimizers.
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<variablelist>
|
||||||
|
<varlistentry>
|
||||||
|
<term>none</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
No optimization is performed. We communicate with the database each and every time
|
||||||
|
an identifier value is needed from the generator.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>pooled-lo</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
The pooled-lo optimizer works on the principle that the increment-value is encoded into
|
||||||
|
the database table/sequence structure. In sequence-terms this means that the sequence
|
||||||
|
is defined with a greater-that-1 increment size. For example, consider a brand new sequence
|
||||||
|
defined as <literal>create sequence my_sequence start with 1 increment by 20</literal>.
|
||||||
|
This sequence essentially defines a "pool" of 20 usable id values each and every time
|
||||||
|
we ask it for its next-value. The pooled-lo optimizer interprets the next-value as the
|
||||||
|
low end of that pool. So when we first ask it for next-value, we'd get 1. We then assume
|
||||||
|
that the valid pool would be the values from 1-20 inclusive. The next call to
|
||||||
|
the sequence would result in 21, which would define 21-40 as the valid range. And so on.
|
||||||
|
The "lo" part of the name indicates that the value from the database table/sequence is
|
||||||
|
interpreted as the pool lo(w) end.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>pooled</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Just like pooled-lo, except that here the value from the table/sequence is interpreted
|
||||||
|
as the high end of the value pool.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
<varlistentry>
|
||||||
|
<term>hilo</term>
|
||||||
|
<term>legacy-hilo</term>
|
||||||
|
<listitem>
|
||||||
|
<para>
|
||||||
|
Define a custom algorithm for generating pools of values based on a single value from
|
||||||
|
a table or sequence. These optimizers are not recommended for use. They are maintained
|
||||||
|
(and mentioned) here simply for use by legacy applications that used these strategies
|
||||||
|
previously.
|
||||||
|
</para>
|
||||||
|
</listitem>
|
||||||
|
</varlistentry>
|
||||||
|
</variablelist>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Applications can also implement and use their own optimizer strategies, as defined by the
|
||||||
|
<interfacename>org.hibernate.id.enhanced.Optimizer</interfacename> contract.
|
||||||
|
</para>
|
||||||
|
</section>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section xml:id="identifiers-derived">
|
<section xml:id="identifiers-derived">
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
@Entity
|
||||||
|
public class Login {
|
||||||
|
@Embeddable
|
||||||
|
public static class PK implements Serializable {
|
||||||
|
private String system;
|
||||||
|
private String username;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private PK pk;
|
||||||
|
...
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
@Entity
|
||||||
|
public class Login {
|
||||||
|
@Embeddable
|
||||||
|
public static class PK implements Serializable {
|
||||||
|
@ManyToOne
|
||||||
|
private System system;
|
||||||
|
private String username;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
@EmbeddedId
|
||||||
|
private PK pk;
|
||||||
|
...
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
@Entity
|
||||||
|
@IdClass(PK.class)
|
||||||
|
public class Login {
|
||||||
|
public static class PK implements Serializable {
|
||||||
|
private String system;
|
||||||
|
private String username;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String system;
|
||||||
|
@Id
|
||||||
|
private String username;
|
||||||
|
...
|
||||||
|
}
|
|
@ -0,0 +1,17 @@
|
||||||
|
@Entity
|
||||||
|
@IdClass(PK.class)
|
||||||
|
public class Login {
|
||||||
|
public static class PK implements Serializable {
|
||||||
|
private System system;
|
||||||
|
private String username;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@ManyToOne
|
||||||
|
private System system;
|
||||||
|
@Id
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
@Entity
|
||||||
|
@IdClass(PK.class)
|
||||||
|
public class LogFile {
|
||||||
|
public static class PK implements Serializable {
|
||||||
|
private String name;
|
||||||
|
private LocalDate date;
|
||||||
|
private Integer uniqueStamp;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
private String name;
|
||||||
|
@Id
|
||||||
|
private LocalDate date;
|
||||||
|
@Id
|
||||||
|
@GeneratedValue
|
||||||
|
private Integer uniqueStamp;
|
||||||
|
...
|
||||||
|
}
|
||||||
|
|
|
@ -196,5 +196,6 @@
|
||||||
* basic types
|
* basic types
|
||||||
* simple id types
|
* simple id types
|
||||||
* generated id types
|
* generated id types
|
||||||
|
* composite ids and many-to-one
|
||||||
* "embedded composite identifiers"
|
* "embedded composite identifiers"
|
||||||
</chapter>
|
</chapter>
|
||||||
|
|
|
@ -21,8 +21,9 @@ Covers reference topics targeting users.
|
||||||
* <strike>Database_Access</strike>
|
* <strike>Database_Access</strike>
|
||||||
* <strike>Transactions</strike>
|
* <strike>Transactions</strike>
|
||||||
* <strike>JNDI</strike>
|
* <strike>JNDI</strike>
|
||||||
* Locking (needs some work)
|
|
||||||
* Fetching (needs some work)
|
* Fetching (needs some work)
|
||||||
|
* Cascading (needs lots of work)
|
||||||
|
* Locking (needs some work)
|
||||||
* Batching (needs lot of work - not started - open questions)
|
* Batching (needs lot of work - not started - open questions)
|
||||||
* Caching (needs some work)
|
* Caching (needs some work)
|
||||||
* Events (need some work)
|
* Events (need some work)
|
||||||
|
|
Loading…
Reference in New Issue