move custom id generators to Advanced + expand it
fix an ambiguity around "natural id" for Steve
This commit is contained in:
parent
674aff1161
commit
a41805d3c2
|
@ -268,6 +268,100 @@ When a value is generated by both inserts _and_ updates, use `@Generated(event={
|
||||||
For columns which should be generated using a SQL `generated always as` clause, prefer the `@GeneratedColumn` annotation, so that Hibernate automatically generates the correct DDL.
|
For columns which should be generated using a SQL `generated always as` clause, prefer the `@GeneratedColumn` annotation, so that Hibernate automatically generates the correct DDL.
|
||||||
====
|
====
|
||||||
|
|
||||||
|
Actually, the `@Generated` and `@GeneratedColumn` annotations are defined in terms of a more generic and user-extensible framework for handling attribute values generated in Java, or by the database.
|
||||||
|
|
||||||
|
[[user-defined-generators]]
|
||||||
|
=== User-defined generators
|
||||||
|
|
||||||
|
JPA doesn't define a standard way to extend the set of id generation strategies, but Hibernate does:
|
||||||
|
|
||||||
|
- the `Generator` hierarchy of interfaces in the package `org.hibernate.generator` lets you define new generators, and
|
||||||
|
- the `@IdGeneratorType` meta-annotation from the package `org.hibernate.annotations` lets you write an annotation which associates a `Generator` type with identifier attributes.
|
||||||
|
|
||||||
|
Furthermore, the `@ValueGenerationType` meta-annotation lets you write an annotation which associates a `Generator` type with a non-`@Id` attribute.
|
||||||
|
|
||||||
|
[NOTE]
|
||||||
|
// .The older APIs are still available in Hibernate 6
|
||||||
|
====
|
||||||
|
These APIs are new in Hibernate 6, and supersede the classic `IdentifierGenerator` interface and `@GenericGenerator` annotation from older versions of Hibernate.
|
||||||
|
However, the older APIs are still available and custom ``IdentifierGenerator``s written for older versions of Hibernate continue to work in Hibernate 6.
|
||||||
|
====
|
||||||
|
|
||||||
|
Hibernate has a range of built-in generators which are defined in terms of this new framework.
|
||||||
|
|
||||||
|
.Built-in generators
|
||||||
|
[cols="20,25,~"]
|
||||||
|
|===
|
||||||
|
| Annotation | Implementation | Purpose
|
||||||
|
|
||||||
|
| `@Generated` | `GeneratedGeneration` | Generically handles database-generated values
|
||||||
|
| `@GeneratedColumn` | `GeneratedAlwaysGeneration` | Handles values generated using `generated always`
|
||||||
|
| `@CurrentTimestamp` | `CurrentTimestampGeneration` | Generic support for database or in-memory generation of creation or update timestamps
|
||||||
|
| `@CreationTimestamp` | `CurrentTimestampGeneration` | A timestamp generated when an entity is first made persistent
|
||||||
|
| `@UpdateTimestamp` | `CurrentTimestampGeneration` | A timestamp generated when an entity is made persistent, and regenerated every time the entity is modified
|
||||||
|
| `@UuidGenerator` | `UuidGenerator` | A more flexible generator for RFC 4122 UUIDs
|
||||||
|
|===
|
||||||
|
|
||||||
|
Furthermore, support for JPA's standard id generation strategies is also defined in terms of this framework.
|
||||||
|
|
||||||
|
As an example, let's look at how `@UuidGenerator` is defined:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@IdGeneratorType(org.hibernate.id.uuid.UuidGenerator.class)
|
||||||
|
@ValueGenerationType(generatedBy = org.hibernate.id.uuid.UuidGenerator.class)
|
||||||
|
@Retention(RUNTIME)
|
||||||
|
@Target({ FIELD, METHOD })
|
||||||
|
public @interface UuidGenerator { ... }
|
||||||
|
----
|
||||||
|
|
||||||
|
`@UuidGenerator` is meta-annotated both `@IdGeneratorType` and `@ValueGenerationType` because it may be used to generate both ids and values of regular attributes.
|
||||||
|
Either way, this `Generator` class does the hard work:
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
public class UuidGenerator
|
||||||
|
// this generator produced values before SQL is executed
|
||||||
|
implements BeforeExecutionGenerator {
|
||||||
|
|
||||||
|
// constructors accept an instance of the @UuidGenerator
|
||||||
|
// annotation, allowing the generator to be "configured"
|
||||||
|
|
||||||
|
// called to create an id generator
|
||||||
|
public UuidGenerator(
|
||||||
|
org.hibernate.annotations.UuidGenerator config,
|
||||||
|
Member idMember,
|
||||||
|
CustomIdGeneratorCreationContext creationContext) {
|
||||||
|
this(config, idMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
// called to create a generator for a regular attribute
|
||||||
|
public UuidGenerator(
|
||||||
|
org.hibernate.annotations.UuidGenerator config,
|
||||||
|
Member member,
|
||||||
|
GeneratorCreationContext creationContext) {
|
||||||
|
this(config, idMember);
|
||||||
|
}
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EnumSet<EventType> getEventTypes() {
|
||||||
|
// UUIDs are only assigned on insert, and never regenerated
|
||||||
|
return INSERT_ONLY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object generate(SharedSessionContractImplementor session, Object owner, Object currentValue, EventType eventType) {
|
||||||
|
// actually generate a UUID and transform it to the required type
|
||||||
|
return valueTransformer.transform( generator.generateUuid( session ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
|
You can find out more about custom generators from the Javadoc for `@IdGeneratorType` and for `org.hibernate.generator`.
|
||||||
|
|
||||||
|
|
||||||
[[naming-strategies]]
|
[[naming-strategies]]
|
||||||
=== Naming strategies
|
=== Naming strategies
|
||||||
|
|
||||||
|
|
|
@ -302,37 +302,29 @@ This fits somewhat uncomfortably with the common practice of annotating the `@Id
|
||||||
====
|
====
|
||||||
|
|
||||||
As you can see, JPA provides quite adequate support for the most common strategies for system-generated ids.
|
As you can see, JPA provides quite adequate support for the most common strategies for system-generated ids.
|
||||||
However, the annotations themselves are a little more intrusive than they should be, and there's no well-defined way to extend this framework to support custom strategies for id generation.
|
However, the annotations themselves are a bit more intrusive than they should be, and there's no well-defined way to extend this framework to support custom strategies for id generation.
|
||||||
Nor may `@GeneratedValue` be used on a property not annotated `@Id`.
|
Nor may `@GeneratedValue` be used on a property not annotated `@Id`.
|
||||||
Since custom id generation is a rather common requirement, Hibernate provides a very carefully-designed framework for user-defined ``Generator``s.
|
Since custom id generation is a rather common requirement, Hibernate provides a very carefully-designed framework for user-defined ``Generator``s, which we'll discuss in <<user-defined-generators>>.
|
||||||
|
|
||||||
[[user-defined-generators]]
|
|
||||||
=== User-defined generators
|
|
||||||
|
|
||||||
JPA doesn't define a standard way to extend the set of id generation strategies, but Hibernate does:
|
|
||||||
|
|
||||||
- the `Generator` hierarchy of interfaces in the package `org.hibernate.generator` lets you define new generators, and
|
|
||||||
- the `@IdGeneratorType` meta-annotation from the package `org.hibernate.annotations` lets you write an annotation which associates a `Generator` type with identifier attributes.
|
|
||||||
|
|
||||||
Furthermore, the `@ValueGenerationType` meta-annotation lets you write an annotation which associates a `Generator` type with a non-`@Id` attribute.
|
|
||||||
|
|
||||||
[NOTE]
|
|
||||||
// .The older APIs are still available in Hibernate 6
|
|
||||||
====
|
|
||||||
These APIs are new in Hibernate 6, and supersede the classic `IdentifierGenerator` interface and `@GenericGenerator` annotation from older versions of Hibernate.
|
|
||||||
However, the older APIs are still available and custom ``IdentifierGenerator``s written for older versions of Hibernate continue to work in Hibernate 6.
|
|
||||||
====
|
|
||||||
|
|
||||||
You can find out more from the Javadoc for `@IdGeneratorType` and for `org.hibernate.generator`.
|
|
||||||
|
|
||||||
[[natural-identifiers]]
|
[[natural-identifiers]]
|
||||||
=== Natural identifiers
|
=== Natural keys as identifiers
|
||||||
|
|
||||||
Not every id maps to a (system-generated) surrogate key.
|
Not every identifier attribute maps to a (system-generated) surrogate key.
|
||||||
Primary keys which are meaningful to the user of the system are called _natural keys_.
|
Primary keys which are meaningful to the user of the system are called _natural keys_.
|
||||||
|
|
||||||
When the primary key of a table is a natural key, we don't annotate the identifier attribute `@GeneratedValue`, and it's the responsibility of the application code to assign a value to the identifier attribute.
|
When the primary key of a table is a natural key, we don't annotate the identifier attribute `@GeneratedValue`, and it's the responsibility of the application code to assign a value to the identifier attribute.
|
||||||
|
|
||||||
|
[source,java]
|
||||||
|
----
|
||||||
|
@Entity
|
||||||
|
class Book {
|
||||||
|
@Id
|
||||||
|
String isbn;
|
||||||
|
|
||||||
|
...
|
||||||
|
}
|
||||||
|
----
|
||||||
|
|
||||||
Of particular interest are natural keys which comprise more than one database column, and such natural keys are called _composite keys_.
|
Of particular interest are natural keys which comprise more than one database column, and such natural keys are called _composite keys_.
|
||||||
|
|
||||||
[[composite-identifiers]]
|
[[composite-identifiers]]
|
||||||
|
@ -477,8 +469,10 @@ And the `@OptimisticLock` annotation lets us selectively exclude certain fields
|
||||||
[[natural-id-attributes]]
|
[[natural-id-attributes]]
|
||||||
=== Natural id attributes
|
=== Natural id attributes
|
||||||
|
|
||||||
Even when an entity has a surrogate key, it should still be possible to write down a combination of fields which uniquely identifies an instance of the entity, from the point of view of the user of the system.
|
Even when an entity has a surrogate key, it should always be possible to write down a combination of fields which uniquely identifies an instance of the entity, from the point of view of the user of the system.
|
||||||
We call this combination of fields a _natural key_.
|
This combination of fields is its natural key.
|
||||||
|
Above, we <<natural-identifiers,considered>> the case where the natural key coincides with the primary key.
|
||||||
|
Here, the natural key is a second unique key of the entity, distinct from its surrogate primary key.
|
||||||
|
|
||||||
[IMPORTANT]
|
[IMPORTANT]
|
||||||
// .What if my entity has no natural key?
|
// .What if my entity has no natural key?
|
||||||
|
|
Loading…
Reference in New Issue