Document value generation;
Moved `@CurrentTimestamp` from src/test/java to src/main/java
This commit is contained in:
parent
34a1fa8c7f
commit
53fc490181
|
@ -1,9 +1,13 @@
|
|||
[[basic]]
|
||||
=== Basic types
|
||||
:modeldir: ../../../../../main/java/org/hibernate/userguide/model
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/mapping
|
||||
:resourcedir: ../../../../../test/resources/org/hibernate/userguide/
|
||||
:converter-sourcedir: ../../../../../../../hibernate-core/src/test/java/org/hibernate/orm/test/mapping/converted/converter
|
||||
:rootProjectDir: ../../../../../../..
|
||||
:documentationProjectDir: {rootProjectDir}/documentation
|
||||
:coreProjectDir: {rootProjectDir}/hibernate-core
|
||||
:core-generated-test-dir: {coreProjectDir}/src/test/java/org/hibernate/orm/test/mapping/generated
|
||||
:modeldir: {documentationProjectDir}/src/main/java/org/hibernate/userguide/model
|
||||
:sourcedir: {documentationProjectDir}/src/test/java/org/hibernate/userguide/mapping
|
||||
:resourcedir: {documentationProjectDir}/src/test/resources/org/hibernate/userguide/
|
||||
:converter-sourcedir: {coreProjectDir}/src/test/java/org/hibernate/orm/test/mapping/converted/converter
|
||||
:extrasdir: extras
|
||||
|
||||
A basic type is a mapping between a Java type and a single database column.
|
||||
|
@ -2082,304 +2086,163 @@ For more about quoting-related configuration properties, check out the <<appendi
|
|||
[[mapping-generated]]
|
||||
==== Generated properties
|
||||
|
||||
Generated properties are properties that have their values generated by the database.
|
||||
Typically, Hibernate applications needed to `refresh` objects that contain any properties for which the database was generating values.
|
||||
Marking properties as generated, however, lets the application delegate this responsibility to Hibernate.
|
||||
When Hibernate issues an SQL INSERT or UPDATE for an entity that has defined generated properties, it immediately issues a select to retrieve the generated values.
|
||||
NOTE:: This section talks about generating values for non-identifier attributes. For discussion of generated identifier values, see <<identifiers-generators>>.
|
||||
|
||||
Properties marked as generated must additionally be _non-insertable_ and _non-updateable_.
|
||||
Only `@Version` and `@Basic` types can be marked as generated.
|
||||
Generated attributes have their values generated as part of performing a SQL INSERT or UPDATE. Applications can generate these
|
||||
values in any number of ways (SQL DEFAULT value, trigger, etc). Typically, the application needs to refresh objects that
|
||||
contain any properties for which the database was generating values, which is a major drawback.
|
||||
|
||||
`NEVER` (the default):: the given property value is not generated within the database.
|
||||
`INSERT`:: the given property value is generated on insert but is not regenerated on subsequent updates. Properties like _creationTimestamp_ fall into this category.
|
||||
`ALWAYS`:: the property value is generated both on insert and update.
|
||||
Applications can also delegate generation to Hibernate, in which case Hibernate will manage the value generation
|
||||
and (potentialfootnote:[Only in-DB generation requires the refresh]) state refresh itself.
|
||||
|
||||
To mark a property as generated, use The Hibernate specific `@Generated` annotation.
|
||||
[IMPORTANT]
|
||||
====
|
||||
Only `@Basic` and `@Version` attributes can be marked as generated.
|
||||
|
||||
[[mapping-generated-Generated]]
|
||||
===== `@Generated` annotation
|
||||
Generated attributes must additionally be _non-insertable_ and _non-updateable_.
|
||||
====
|
||||
|
||||
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Generated.html[`@Generated`] annotation is used so that Hibernate can fetch the currently annotated property after the entity has been persisted or updated.
|
||||
For this reason, the `@Generated` annotation accepts a https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/GenerationTime.html[`GenerationTime`] enum value.
|
||||
Hibernate supports both in-VM and in-DB generation. A generation that uses the current JVM timestamp as the
|
||||
generated value is an example of an in-VM strategy. A generation that uses the database's `current_timestamp`
|
||||
function is an example of an in-DB strategy.
|
||||
|
||||
Considering the following entity:
|
||||
Hibernate supports the following timing (when) for generation:
|
||||
|
||||
[[mapping-generated-Generated-example]]
|
||||
.`@Generated` mapping example
|
||||
`NEVER` (the default):: the given attribute value is not generated
|
||||
`INSERT`:: the attribute value is generated on insert but is not regenerated on subsequent updates
|
||||
`ALWAYS`:: the attribute value is generated both on insert and update.
|
||||
|
||||
Hibernate supports multiple ways to mark an attribute as generated:
|
||||
|
||||
* Using the dedicated generators provided by Hibernate
|
||||
* `@CurrentTimestamp` - <<mapping-generated-CurrentTimestamp>>
|
||||
* `@CreationTimestamp` - <<mapping-generated-CreationTimestamp>>
|
||||
* `@UpdateTimestamp` - <<mapping-generated-UpdateTimestamp>>
|
||||
* `@Generated` - <<mapping-generated-Generated>>
|
||||
* `@GeneratorType` - is deprecated and not covered here
|
||||
* Using a custom generation strategy - <<mapping-generated-custom>>
|
||||
|
||||
|
||||
[[mapping-generated-CurrentTimestamp]]
|
||||
===== `@CurrentTimestamp`
|
||||
|
||||
The `@CurrentTimestamp` annotation is an in-DB strategy that can be configured for either INSERT or ALWAYS timing.
|
||||
It uses the database's `current_timestamp` function as the generated value
|
||||
|
||||
[[mapping-generated-provided-CurrentTimestamp-ex1]]
|
||||
.`@UpdateTimestamp` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/GeneratedTest.java[tags=mapping-generated-Generated-example]
|
||||
include::{core-generated-test-dir}/CurrentTimestampAnnotationTests.java[tags=mapping-generated-CurrentTimestamp-ex1]
|
||||
----
|
||||
====
|
||||
|
||||
When the `Person` entity is persisted, Hibernate is going to fetch the calculated `fullName` column from the database,
|
||||
which concatenates the first, middle, and last name.
|
||||
|
||||
[[mapping-generated-Generated-persist-example]]
|
||||
.`@Generated` persist example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/GeneratedTest.java[tags=mapping-generated-Generated-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-Generated-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The same goes when the `Person` entity is updated.
|
||||
Hibernate is going to fetch the calculated `fullName` column from the database after the entity is modified.
|
||||
|
||||
[[mapping-generated-Generated-update-example]]
|
||||
.`@Generated` update example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/GeneratedTest.java[tags=mapping-generated-Generated-update-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-Generated-update-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[mapping-generated-GeneratorType]]
|
||||
===== `@GeneratorType` annotation
|
||||
|
||||
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/GeneratorType.html[`@GeneratorType`] annotation is used so that
|
||||
you can provide a custom generator to set the value of the currently annotated property.
|
||||
|
||||
For this reason, the `@GeneratorType` annotation accepts a https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/GenerationTime.html[`GenerationTime`] enum value
|
||||
and a custom https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/ValueGenerator.html[`ValueGenerator`] class type.
|
||||
|
||||
Considering the following entity:
|
||||
|
||||
[[mapping-generated-GeneratorType-example]]
|
||||
.`@GeneratorType` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/GeneratorTypeTest.java[tags=mapping-generated-GeneratorType-example]
|
||||
----
|
||||
====
|
||||
|
||||
When the `Person` entity is persisted, Hibernate is going to populate the `createdBy` column with the currently logged user.
|
||||
|
||||
[[mapping-generated-GeneratorType-persist-example]]
|
||||
.`@GeneratorType` persist example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/GeneratorTypeTest.java[tags=mapping-generated-GeneratorType-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-GeneratorType-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
The same goes when the `Person` entity is updated.
|
||||
Hibernate is going to populate the `updatedBy` column with the currently logged user.
|
||||
|
||||
[[mapping-generated-GeneratorType-update-example]]
|
||||
.`@GeneratorType` update example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/GeneratorTypeTest.java[tags=mapping-generated-GeneratorType-update-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-GeneratorType-update-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[mapping-generated-CreationTimestamp]]
|
||||
===== `@CreationTimestamp` annotation
|
||||
===== `@CreationTimestamp`
|
||||
|
||||
The `@CreationTimestamp` annotation instructs Hibernate to set the annotated entity attribute with the current timestamp value of the JVM
|
||||
when the entity is being persisted.
|
||||
The `@CreationTimestamp` annotation is an in-VM `INSERT` strategy. Hibernate will use
|
||||
the current timestamp of the JVM as the insert value for the attribute.
|
||||
|
||||
The supported property types are:
|
||||
|
||||
- `java.util.Date`
|
||||
- `java.util.Calendar`
|
||||
- `java.sql.Date`
|
||||
- `java.sql.Time`
|
||||
- `java.sql.Timestamp`
|
||||
Supports most temporal types (`java.time.Instant`, `java.util.Date`, `java.util.Calendar`, etc)
|
||||
|
||||
[[mapping-generated-CreationTimestamp-example]]
|
||||
.`@CreationTimestamp` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/CreationTimestampTest.java[tags=mapping-generated-CreationTimestamp-example]
|
||||
include::{sourcedir}/generated/CreationTimestampTest.java[tags=mapping-generated-provided-creation-ex1]
|
||||
----
|
||||
====
|
||||
|
||||
When the `Event` entity is persisted, Hibernate is going to populate the underlying `timestamp` column with the current JVM timestamp value:
|
||||
While inserting the `Event`, Hibernate will populate the underlying `timestamp` column with the current JVM timestamp value
|
||||
|
||||
[[mapping-generated-CreationTimestamp-persist-example]]
|
||||
.`@CreationTimestamp` persist example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/CreationTimestampTest.java[tags=mapping-generated-CreationTimestamp-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-CreationTimestamp-persist-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
[[mapping-generated-UpdateTimestamp]]
|
||||
===== `@UpdateTimestamp` annotation
|
||||
|
||||
The `@UpdateTimestamp` annotation instructs Hibernate to set the annotated entity attribute with the current timestamp value of the JVM
|
||||
when the entity is being persisted.
|
||||
The `@UpdateTimestamp` annotation is an in-VM `INSERT` strategy. Hibernate will use
|
||||
the current timestamp of the JVM as the insert and update value for the attribute.
|
||||
|
||||
The supported property types are:
|
||||
Supports most temporal types (`java.time.Instant`, `java.util.Date`, `java.util.Calendar`, etc)
|
||||
|
||||
- `java.util.Date`
|
||||
- `java.util.Calendar`
|
||||
- `java.sql.Date`
|
||||
- `java.sql.Time`
|
||||
- `java.sql.Timestamp`
|
||||
|
||||
[[mapping-generated-UpdateTimestamp-example]]
|
||||
[[mapping-generated-provided-update-ex1]]
|
||||
.`@UpdateTimestamp` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/UpdateTimestampTest.java[tags=mapping-generated-UpdateTimestamp-example]
|
||||
include::{sourcedir}/generated/UpdateTimestampTest.java[tags=mapping-generated-provided-update-ex1]
|
||||
----
|
||||
====
|
||||
|
||||
When the `Bid` entity is persisted, Hibernate is going to populate the underlying `updated_on` column with the current JVM timestamp value:
|
||||
|
||||
[[mapping-generated-UpdateTimestamp-persist-example]]
|
||||
.`@UpdateTimestamp` persist example
|
||||
|
||||
[[mapping-generated-Generated]]
|
||||
===== `@Generated` annotation
|
||||
|
||||
The `@Generated` annotation is an in-DB strategy that can be configured for either INSERT or ALWAYS timing
|
||||
|
||||
This is the legacy mapping for in-DB generated values.
|
||||
|
||||
|
||||
[[mapping-generated-provided-Generated]]
|
||||
.`@Generated` mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/UpdateTimestampTest.java[tags=mapping-generated-UpdateTimestamp-persist-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-UpdateTimestamp-persist-example.sql[]
|
||||
include::{sourcedir}/generated/GeneratedTest.java[tags=mapping-generated-provided-generated]
|
||||
----
|
||||
====
|
||||
|
||||
When updating the `Bid` entity, Hibernate is going to modify the `updated_on` column with the current JVM timestamp value:
|
||||
|
||||
[[mapping-generated-UpdateTimestamp-update-example]]
|
||||
.`@UpdateTimestamp` update example
|
||||
|
||||
[[mapping-generated-custom]]
|
||||
===== Custom generation strategy
|
||||
|
||||
Hibernate also supports value generation via a pluggable API using `@ValueGenerationType` and `AnnotationValueGeneration`
|
||||
allowing users to define any generation strategy they wish.
|
||||
|
||||
Let's look at an example of generating UUID values. First the attribute mapping
|
||||
|
||||
[[mapping-generated-custom-ex1]]
|
||||
.Custom generation mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/UpdateTimestampTest.java[tags=mapping-generated-UpdateTimestamp-update-example]
|
||||
----
|
||||
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-generated-UpdateTimestamp-update-example.sql[]
|
||||
include::{core-generated-test-dir}/temporals/GeneratedUuidTests.java[tags=mapping-generated-custom-ex1]
|
||||
----
|
||||
====
|
||||
|
||||
[[mapping-generated-ValueGenerationType]]
|
||||
===== `@ValueGenerationType` meta-annotation
|
||||
This example makes use of an annotation named `@GeneratedUuidValue` - but where is that annotation defined? This is a custom
|
||||
annotations provided by the application.
|
||||
|
||||
Hibernate 4.3 introduced the `@ValueGenerationType` meta-annotation, which is a new approach to declaring generated attributes or customizing generators.
|
||||
|
||||
`@Generated` has been retrofitted to use the `@ValueGenerationType` meta-annotation.
|
||||
But `@ValueGenerationType` exposes more features than what `@Generated` currently supports, and,
|
||||
to leverage some of those features, you'd simply wire up a new generator annotation.
|
||||
|
||||
As you'll see in the following examples, the `@ValueGenerationType` meta-annotation is used when declaring the custom annotation used to mark the entity properties that need a specific generation strategy.
|
||||
The actual generation logic must be added to the class that implements the `AnnotationValueGeneration` interface.
|
||||
|
||||
[[mapping-database-generated-value]]
|
||||
====== Database-generated values
|
||||
|
||||
For example, let's say we want the timestamps to be generated by calls to the standard ANSI SQL function `current_timestamp` (rather than triggers or DEFAULT values):
|
||||
|
||||
[[mapping-database-generated-value-example]]
|
||||
.A `ValueGenerationType` mapping for database generation
|
||||
[[mapping-generated-custom-ex2]]
|
||||
.Custom generation mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/DatabaseValueGenerationTest.java[tags=mapping-database-generated-value-example]
|
||||
include::{core-generated-test-dir}/temporals/GeneratedUuidTests.java[tags=mapping-generated-custom-ex2]
|
||||
----
|
||||
====
|
||||
|
||||
When persisting an `Event` entity, Hibernate generates the following SQL statement:
|
||||
The `@ValueGenerationType( generatedBy = UuidValueGeneration.class )` here is the important piece; it tells
|
||||
Hibernate how to generate values for the attribute - here it will use the specified `UuidValueGeneration` class
|
||||
|
||||
====
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-database-generated-value-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
As you can see, the `current_timestamp` value was used for assigning the `timestamp` column value.
|
||||
|
||||
[[mapping-in-memory-generated-value]]
|
||||
====== In-memory-generated values
|
||||
|
||||
If the timestamp value needs to be generated in-memory, the following mapping must be used instead:
|
||||
|
||||
[[mapping-in-memory-generated-value-example]]
|
||||
.A `ValueGenerationType` mapping for in-memory value generation
|
||||
[[mapping-generated-custom-ex3]]
|
||||
.Custom generation mapping example
|
||||
====
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/generated/InMemoryValueGenerationTest.java[tags=mapping-in-memory-generated-value-example]
|
||||
include::{core-generated-test-dir}/temporals/GeneratedUuidTests.java[tags=mapping-generated-custom-ex3]
|
||||
----
|
||||
====
|
||||
|
||||
When persisting an `Event` entity, Hibernate generates the following SQL statement:
|
||||
|
||||
====
|
||||
[source, SQL, indent=0]
|
||||
----
|
||||
include::{extrasdir}/basic/mapping-in-memory-generated-value-example.sql[]
|
||||
----
|
||||
====
|
||||
|
||||
As you can see, the `new Date()` object value was used for assigning the `timestamp` column value.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
See https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/ValueGenerationType.html[`@ValueGenerationType`]
|
||||
and https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/tuple/AnnotationValueGeneration.html[`AnnotationValueGeneration`]
|
||||
for details of each contract
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -41,7 +41,7 @@ public class CreationTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::mapping-generated-CreationTimestamp-example[]
|
||||
//tag::mapping-generated-provided-creation-ex1[]
|
||||
@Entity(name = "Event")
|
||||
public static class Event {
|
||||
|
||||
|
@ -54,7 +54,7 @@ public class CreationTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
|||
private Date timestamp;
|
||||
|
||||
//Constructors, getters, and setters are omitted for brevity
|
||||
//end::mapping-generated-CreationTimestamp-example[]
|
||||
//end::mapping-generated-provided-creation-ex1[]
|
||||
|
||||
public Event() {}
|
||||
|
||||
|
@ -65,7 +65,7 @@ public class CreationTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
|||
public Date getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
//tag::mapping-generated-CreationTimestamp-example[]
|
||||
//tag::mapping-generated-provided-creation-ex1[]
|
||||
}
|
||||
//end::mapping-generated-CreationTimestamp-example[]
|
||||
//end::mapping-generated-provided-creation-ex1[]
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ public class GeneratedTest extends BaseEntityManagerFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::mapping-generated-Generated-example[]
|
||||
//tag::mapping-generated-provided-generated[]
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
|
@ -99,7 +99,7 @@ public class GeneratedTest extends BaseEntityManagerFunctionalTestCase {
|
|||
")")
|
||||
private String fullName;
|
||||
|
||||
//end::mapping-generated-Generated-example[]
|
||||
//end::mapping-generated-provided-generated[]
|
||||
public Person() {}
|
||||
|
||||
public Long getId() {
|
||||
|
@ -169,7 +169,7 @@ public class GeneratedTest extends BaseEntityManagerFunctionalTestCase {
|
|||
public String getFullName() {
|
||||
return fullName;
|
||||
}
|
||||
//tag::mapping-generated-Generated-example[]
|
||||
//tag::mapping-generated-provided-generated[]
|
||||
}
|
||||
//end::mapping-generated-Generated-example[]
|
||||
//end::mapping-generated-provided-generated[]
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public class UpdateTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
//tag::mapping-generated-UpdateTimestamp-example[]
|
||||
//tag::mapping-generated-provided-update-ex1[]
|
||||
@Entity(name = "Bid")
|
||||
public static class Bid {
|
||||
|
||||
|
@ -72,7 +72,7 @@ public class UpdateTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
//Getters and setters are omitted for brevity
|
||||
|
||||
//end::mapping-generated-UpdateTimestamp-example[]
|
||||
//end::mapping-generated-provided-update-ex1[]
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
|
@ -101,7 +101,7 @@ public class UpdateTimestampTest extends BaseEntityManagerFunctionalTestCase {
|
|||
public void setCents(Long cents) {
|
||||
this.cents = cents;
|
||||
}
|
||||
//tag::mapping-generated-UpdateTimestamp-example[]
|
||||
//tag::mapping-generated-provided-update-ex1[]
|
||||
}
|
||||
//end::mapping-generated-UpdateTimestamp-example[]
|
||||
//end::mapping-generated-provided-update-ex1[]
|
||||
}
|
||||
|
|
|
@ -4,19 +4,28 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.generated.temporals;
|
||||
package org.hibernate.annotations;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hibernate.annotations.ValueGenerationType;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
|
||||
/**
|
||||
* Specifies to use the database `current_timestamp` function for generating
|
||||
* values for the associated attribute based on {@link #timing()}
|
||||
*
|
||||
* @see CurrentTimestampGeneration
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@ValueGenerationType(generatedBy = CurrentTimestampGeneration.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target( { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE } )
|
||||
@Inherited
|
||||
public @interface CurrentTimestamp {
|
||||
GenerationTiming timing();
|
||||
}
|
|
@ -4,23 +4,26 @@
|
|||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.generated.temporals;
|
||||
package org.hibernate.annotations;
|
||||
|
||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
|
||||
/**
|
||||
* Value generation strategy for using the database `current_timestamp` function to generate
|
||||
* the values
|
||||
*
|
||||
* @see CurrentTimestamp
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CurrentTimestampGeneration implements AnnotationValueGeneration<CurrentTimestamp> {
|
||||
private GenerationTiming timing;
|
||||
private Class<?> propertyType;
|
||||
|
||||
@Override
|
||||
public void initialize(CurrentTimestamp annotation, Class<?> propertyType) {
|
||||
this.timing = annotation.timing();
|
||||
this.propertyType = propertyType;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -30,6 +33,7 @@ public class CurrentTimestampGeneration implements AnnotationValueGeneration<Cur
|
|||
|
||||
@Override
|
||||
public ValueGenerator<?> getValueGenerator() {
|
||||
// ValueGenerator is only used for in-VM generations
|
||||
return null;
|
||||
}
|
||||
|
|
@ -11,6 +11,7 @@ import java.lang.annotation.Retention;
|
|||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
import org.hibernate.tuple.VmValueGeneration;
|
||||
|
||||
|
@ -20,10 +21,13 @@ import org.hibernate.tuple.VmValueGeneration;
|
|||
* annotated property.
|
||||
*
|
||||
* @author Gunnar Morling
|
||||
*
|
||||
* @deprecated Most uses can be changed to use {@link ValueGenerationType} + {@link AnnotationValueGeneration}
|
||||
*/
|
||||
@ValueGenerationType( generatedBy = VmValueGeneration.class )
|
||||
@Retention( RetentionPolicy.RUNTIME )
|
||||
@Target( value = { ElementType.FIELD, ElementType.METHOD } )
|
||||
@Deprecated
|
||||
public @interface GeneratorType {
|
||||
|
||||
/**
|
||||
|
|
|
@ -11,7 +11,7 @@ import javax.persistence.Entity;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.orm.test.mapping.generated.temporals.CurrentTimestamp;
|
||||
import org.hibernate.annotations.CurrentTimestamp;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
@ -24,9 +24,9 @@ import static org.assertj.core.api.Assertions.assertThat;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel( annotatedClasses = GeneratedValueAnnotationTests.AuditedEntity.class )
|
||||
@DomainModel( annotatedClasses = CurrentTimestampAnnotationTests.AuditedEntity.class )
|
||||
@SessionFactory
|
||||
public class GeneratedValueAnnotationTests {
|
||||
public class CurrentTimestampAnnotationTests {
|
||||
@Test
|
||||
public void test(SessionFactoryScope scope) {
|
||||
final AuditedEntity created = scope.fromTransaction( (session) -> {
|
||||
|
@ -71,11 +71,13 @@ public class GeneratedValueAnnotationTests {
|
|||
public Integer id;
|
||||
public String name;
|
||||
|
||||
//tag::mapping-generated-CurrentTimestamp-ex1[]
|
||||
@CurrentTimestamp( timing = GenerationTiming.INSERT )
|
||||
public Instant createdAt;
|
||||
|
||||
@CurrentTimestamp( timing = GenerationTiming.ALWAYS )
|
||||
public Instant lastUpdatedAt;
|
||||
//end::mapping-generated-CurrentTimestamp-ex1[]
|
||||
|
||||
public AuditedEntity() {
|
||||
}
|
|
@ -14,7 +14,7 @@ import javax.persistence.Table;
|
|||
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.UpdateTimestamp;
|
||||
import org.hibernate.orm.test.mapping.generated.temporals.CurrentTimestamp;
|
||||
import org.hibernate.annotations.CurrentTimestamp;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
|
|
@ -11,6 +11,7 @@ import javax.persistence.Entity;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.CurrentTimestamp;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
|
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.orm.test.mapping.generated.temporals;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.util.UUID;
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.ValueGenerationType;
|
||||
import org.hibernate.tuple.AnnotationValueGeneration;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
import org.hibernate.tuple.ValueGenerator;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
/**
|
||||
* Test illustrating usage of {@link ValueGenerationType}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel( annotatedClasses = GeneratedUuidTests.GeneratedUuidEntity.class )
|
||||
@SessionFactory
|
||||
public class GeneratedUuidTests {
|
||||
@Test
|
||||
public void test(SessionFactoryScope scope) {
|
||||
final GeneratedUuidEntity created = scope.fromTransaction( (session) -> {
|
||||
final GeneratedUuidEntity entity = new GeneratedUuidEntity( 1, "tsifr" );
|
||||
session.persist( entity );
|
||||
return entity;
|
||||
} );
|
||||
|
||||
assertThat( created.createdUuid ).isNotNull();
|
||||
assertThat( created.updatedUuid ).isNotNull();
|
||||
|
||||
created.name = "first";
|
||||
|
||||
// then changing
|
||||
final GeneratedUuidEntity merged = scope.fromTransaction( (session) -> {
|
||||
return (GeneratedUuidEntity) session.merge( created );
|
||||
} );
|
||||
|
||||
assertThat( merged ).isNotNull();
|
||||
assertThat( merged.createdUuid ).isNotNull();
|
||||
assertThat( merged.updatedUuid ).isNotNull();
|
||||
assertThat( merged.createdUuid ).isEqualTo( created.createdUuid );
|
||||
assertThat( merged.updatedUuid ).isNotEqualTo( created.updatedUuid );
|
||||
|
||||
assertThat( merged ).isNotNull();
|
||||
|
||||
// lastly, make sure we can load it..
|
||||
final GeneratedUuidEntity loaded = scope.fromTransaction( (session) -> {
|
||||
return session.get( GeneratedUuidEntity.class, 1 );
|
||||
} );
|
||||
|
||||
assertThat( loaded ).isNotNull();
|
||||
|
||||
assertThat( loaded.createdUuid ).isEqualTo( merged.createdUuid );
|
||||
assertThat( loaded.updatedUuid ).isEqualTo( merged.updatedUuid );
|
||||
}
|
||||
|
||||
//tag::mapping-generated-custom-ex2[]
|
||||
@ValueGenerationType( generatedBy = UuidValueGeneration.class )
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target( { ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE } )
|
||||
@Inherited
|
||||
public @interface GeneratedUuidValue {
|
||||
GenerationTiming timing();
|
||||
}
|
||||
//end::mapping-generated-custom-ex2[]
|
||||
|
||||
//tag::mapping-generated-custom-ex3[]
|
||||
public static class UuidValueGeneration implements AnnotationValueGeneration<GeneratedUuidValue>, ValueGenerator<UUID> {
|
||||
private GenerationTiming timing;
|
||||
|
||||
@Override
|
||||
public void initialize(GeneratedUuidValue annotation, Class<?> propertyType) {
|
||||
timing = annotation.timing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public GenerationTiming getGenerationTiming() {
|
||||
return timing;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueGenerator<?> getValueGenerator() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean referenceColumnInSql() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID generateValue(Session session, Object owner) {
|
||||
return UUID.randomUUID();
|
||||
}
|
||||
}
|
||||
//end::mapping-generated-custom-ex3[]
|
||||
|
||||
@Entity( name = "GeneratedUuidEntity" )
|
||||
@Table( name = "t_gen_uuid" )
|
||||
public static class GeneratedUuidEntity {
|
||||
@Id
|
||||
public Integer id;
|
||||
@Basic
|
||||
public String name;
|
||||
|
||||
//tag::mapping-generated-custom-ex1[]
|
||||
@GeneratedUuidValue( timing = GenerationTiming.INSERT )
|
||||
public UUID createdUuid;
|
||||
|
||||
@GeneratedUuidValue( timing = GenerationTiming.ALWAYS )
|
||||
public UUID updatedUuid;
|
||||
//end::mapping-generated-custom-ex1[]
|
||||
|
||||
public GeneratedUuidEntity() {
|
||||
}
|
||||
|
||||
public GeneratedUuidEntity(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,6 +11,7 @@ import javax.persistence.Entity;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.hibernate.annotations.CurrentTimestamp;
|
||||
import org.hibernate.tuple.GenerationTiming;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
|
|
Loading…
Reference in New Issue