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