HHH-15663 add @Generated(sql=....)
This commit is contained in:
parent
f6e65dc91a
commit
cea6774f01
|
@ -14,23 +14,35 @@ import java.lang.annotation.Target;
|
|||
import org.hibernate.tuple.GeneratedValueGeneration;
|
||||
|
||||
/**
|
||||
* Specifies that the value of the annotated property is generated by the database.
|
||||
* The generated value will be automatically retrieved using a SQL {@code SELECT}
|
||||
* after it is generated.
|
||||
* Specifies that the value of the annotated property is generated by the
|
||||
* database. The generated value will be automatically retrieved using a
|
||||
* SQL {@code select} after it is generated.
|
||||
* <p>
|
||||
* {@code Generated} relieves the program of the need to call
|
||||
* {@link org.hibernate.Session#refresh(Object)} explicitly to synchronize state
|
||||
* held in memory with state generated by the database when a SQL {@code INSERT}
|
||||
* or {@code UPDATE} is executed.
|
||||
* {@code @Generated} relieves the program of the need to explicitly call
|
||||
* {@link org.hibernate.Session#refresh(Object)} to synchronize state held
|
||||
* in memory with state generated by the database when a SQL {@code insert}
|
||||
* or {@code update} is executed.
|
||||
* <p>
|
||||
* This is most useful for working with database tables where a column value is
|
||||
* populated by a database trigger. A second possible scenario is the use of
|
||||
* {@code Generated(INSERT)} with {@link ColumnDefault}.
|
||||
* This is most useful when:
|
||||
* <ul>
|
||||
* <li>For identity/autoincrement columns mapped to an identifier property,
|
||||
* use {@link jakarta.persistence.GeneratedValue}.
|
||||
* <li>For columns with a {@code generated always as} clause, prefer the
|
||||
* {@link GeneratedColumn} annotation.
|
||||
* <li>a database table has a column value populated by a database trigger,
|
||||
* <li>a mapped column has a default value defined in DDL, in which case
|
||||
* {@code Generated(INSERT)} is used in conjunction with
|
||||
* {@link ColumnDefault},
|
||||
* <li>a {@linkplain #sql() SQL expression} is used to compute the value of
|
||||
* a mapped column, or
|
||||
* <li>when a custom SQL {@link SQLInsert insert} or {@link SQLUpdate update}
|
||||
* statement specified by an entity assigns a value to the annotated
|
||||
* property of the entity, or {@linkplain #writable() transforms} the
|
||||
* value currently assigned to the annotated property.
|
||||
* </ul>
|
||||
* On the other hand:
|
||||
* <ul>
|
||||
* <li>for identity/autoincrement columns mapped to an identifier property,
|
||||
* use {@link jakarta.persistence.GeneratedValue}, and
|
||||
* <li>for columns with a {@code generated always as} clause, prefer the
|
||||
* {@link GeneratedColumn} annotation, so that Hibernate automatically
|
||||
* generates the correct DDL.
|
||||
* </ul>
|
||||
*
|
||||
* @author Emmanuel Bernard
|
||||
|
@ -44,22 +56,33 @@ import org.hibernate.tuple.GeneratedValueGeneration;
|
|||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Generated {
|
||||
/**
|
||||
* Specifies the events that cause the value to be generated by the database.
|
||||
* Specifies the events that cause the value to be generated by the
|
||||
* database.
|
||||
* <ul>
|
||||
* <li>If {@link GenerationTime#INSERT}, the generated value will be selected
|
||||
* after each SQL {@code INSERT} statement is executed.
|
||||
* <li>If {@link GenerationTime#ALWAYS}, the generated value will be selected
|
||||
* after each SQL {@code INSERT} or {@code UPDATE} statement is executed.
|
||||
* <li>If {@link GenerationTime#INSERT}, the generated value will be
|
||||
* selected after each SQL {@code insert} statement is executed.
|
||||
* <li>If {@link GenerationTime#ALWAYS}, the generated value will be
|
||||
* selected after each SQL {@code insert} or {@code update}
|
||||
* statement is executed.
|
||||
* </ul>
|
||||
*/
|
||||
GenerationTime value();
|
||||
|
||||
/**
|
||||
* Determines if the column mapped by the annotated property is included in SQL
|
||||
* {@code INSERT} and {@code UPDATE} statements. By default, it is excluded.
|
||||
* A SQL expression used to generate the value of the column mapped by
|
||||
* the annotated property. The expression is included in generated SQL
|
||||
* {@code insert} and {@code update} statements.
|
||||
*/
|
||||
String sql() default "";
|
||||
|
||||
/**
|
||||
* Determines if the value currently assigned to the annotated property
|
||||
* is included in SQL {@code insert} and {@code update} statements. This
|
||||
* is useful if the generated value is obtained by transforming the
|
||||
* assigned property value as it is being written.
|
||||
*
|
||||
* @return {@code true} if the mapped column should be included in SQL
|
||||
* {@code INSERT} and {@code UPDATE} statements.
|
||||
* @return {@code true} if the current value should be included in SQL
|
||||
* {@code insert} and {@code update} statements.
|
||||
*/
|
||||
boolean writable() default false;
|
||||
}
|
||||
|
|
|
@ -29,11 +29,17 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* and has no corresponding JDBC parameter in the custom SQL, it must be mapped
|
||||
* using {@link jakarta.persistence.Column#insertable insertable=false}.
|
||||
* <p>
|
||||
* A custom SQL insert statement might transform the column values as they
|
||||
* are written. In this case, the state of the entity held in memory loses
|
||||
* synchronization with the database after the insert is executed unless
|
||||
* A custom SQL insert statement might assign a value to a mapped column as it
|
||||
* is written. In this case, the corresponding property of the entity remains
|
||||
* unassigned after the insert is executed unless
|
||||
* {@link Generated @Generated(INSERT)} is specified, forcing Hibernate to
|
||||
* reread the state of the entity after each insert.
|
||||
* <p>
|
||||
* Similarly, a custom insert statement might transform a mapped column value
|
||||
* as it is written. In this case, the state of the entity held in memory
|
||||
* loses synchronization with the database after the insert is executed unless
|
||||
* {@link Generated @Generated(value=INSERT, writable=true)} is specified,
|
||||
* forcing Hibernate to reread the state of the entity after each insert.
|
||||
* again forcing Hibernate to reread the state of the entity after each insert.
|
||||
*
|
||||
* @author Laszlo Benke
|
||||
*/
|
||||
|
|
|
@ -32,11 +32,17 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|||
* and has no corresponding JDBC parameter in the custom SQL, it must be mapped
|
||||
* using {@link jakarta.persistence.Column#updatable() updatable=false}.
|
||||
* <p>
|
||||
* A custom SQL update statement might transform the column values as they
|
||||
* are written. In this case, the state of the entity held in memory loses
|
||||
* synchronization with the database after the update is executed unless
|
||||
* A custom SQL update statement might assign a value to a mapped column as it
|
||||
* is written. In this case, the corresponding property of the entity remains
|
||||
* unassigned after the update is executed unless
|
||||
* {@link Generated @Generated(ALWAYS)} is specified, forcing Hibernate to
|
||||
* reread the state of the entity after each update.
|
||||
* <p>
|
||||
* Similarly, a custom update statement might transform a mapped column value
|
||||
* as it is written. In this case, the state of the entity held in memory
|
||||
* loses synchronization with the database after the update is executed unless
|
||||
* {@link Generated @Generated(value=ALWAYS, writable=true)} is specified,
|
||||
* forcing Hibernate to reread the state of the entity after each update.
|
||||
* again forcing Hibernate to reread the state of the entity after each update.
|
||||
*
|
||||
* @author Laszlo Benke
|
||||
*/
|
||||
|
|
|
@ -390,7 +390,7 @@ public class PropertyBinder {
|
|||
return NoValueGeneration.INSTANCE;
|
||||
}
|
||||
|
||||
if ( !valueGeneration.writeColumn() ) {
|
||||
if ( !valueGeneration.writePropertyValue() ) {
|
||||
// if we have an in-db generator, mark it as not insertable nor updatable
|
||||
insertable = false;
|
||||
updatable = false;
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.tuple;
|
|||
|
||||
import org.hibernate.annotations.Generated;
|
||||
|
||||
import static org.hibernate.internal.util.StringHelper.isEmpty;
|
||||
|
||||
/**
|
||||
* A {@link AnnotationValueGeneration} which marks a property as generated in the database.
|
||||
*
|
||||
|
@ -18,6 +20,7 @@ public class GeneratedValueGeneration implements AnnotationValueGeneration<Gener
|
|||
|
||||
private GenerationTiming timing;
|
||||
private boolean writable;
|
||||
private String sql;
|
||||
|
||||
public GeneratedValueGeneration() {
|
||||
}
|
||||
|
@ -29,7 +32,8 @@ public class GeneratedValueGeneration implements AnnotationValueGeneration<Gener
|
|||
@Override
|
||||
public void initialize(Generated annotation, Class<?> propertyType) {
|
||||
timing = annotation.value().getEquivalent();
|
||||
writable = annotation.writable();
|
||||
sql = isEmpty( annotation.sql() ) ? null : annotation.sql();
|
||||
writable = annotation.writable() || sql != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -50,7 +54,7 @@ public class GeneratedValueGeneration implements AnnotationValueGeneration<Gener
|
|||
|
||||
@Override
|
||||
public String getDatabaseGeneratedReferencedColumnValue() {
|
||||
return null;
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,18 @@ package org.hibernate.tuple;
|
|||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Describes the generation of values of a certain property of an entity. Property values might
|
||||
* be generated in Java, or by the database.
|
||||
* Describes the generation of values of a certain field or property of an entity. A generated
|
||||
* value might be generated in Java, or by the database.
|
||||
* <ul>
|
||||
* <li>Java value generation is the responsibility of an associated {@link ValueGenerator}.
|
||||
* In this case, the generated value is written to the database just like any other field
|
||||
* or property value.
|
||||
* <li>A value generated by the database might be generated implicitly, by a trigger, or using
|
||||
* a {@code default} column value specified in DDL, for example, or it might be generated
|
||||
* by a SQL expression occurring explicitly in the SQL {@code insert} or {@code update}
|
||||
* statement. In this case, the generated value is retrieved from the database using a SQL
|
||||
* {@code select}.
|
||||
* </ul>
|
||||
*
|
||||
* @see org.hibernate.annotations.ValueGenerationType
|
||||
* @see org.hibernate.annotations.Generated
|
||||
|
@ -97,8 +107,10 @@ public interface ValueGeneration extends Serializable {
|
|||
* <li>{@link #referenceColumnInSql()} is {@code true} and
|
||||
* {@link #getDatabaseGeneratedReferencedColumnValue()} returns {@code null}.
|
||||
* </ul>
|
||||
*
|
||||
* @see org.hibernate.annotations.Generated#writable()
|
||||
*/
|
||||
default boolean writeColumn() {
|
||||
default boolean writePropertyValue() {
|
||||
return !generatedByDatabase() // value generated in memory and then written as normal
|
||||
// current value of property of entity instance written completely as normal
|
||||
|| referenceColumnInSql() && getDatabaseGeneratedReferencedColumnValue()==null;
|
||||
|
|
Loading…
Reference in New Issue