allow use of SelectGenerator from annotations
- generalize @GenericGenerator to any Generator - add tests for @GenericGenerator(type=SelectGenerator) - move some logic for choosing the right InsertGeneratedIdentifierDelegate to the generators themselves
This commit is contained in:
parent
6536fe0d72
commit
e8c2824976
|
@ -6,7 +6,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.annotations;
|
package org.hibernate.annotations;
|
||||||
|
|
||||||
import org.hibernate.generator.InMemoryGenerator;
|
import org.hibernate.generator.Generator;
|
||||||
|
|
||||||
import java.lang.annotation.Repeatable;
|
import java.lang.annotation.Repeatable;
|
||||||
import java.lang.annotation.Retention;
|
import java.lang.annotation.Retention;
|
||||||
|
@ -19,11 +19,10 @@ import static java.lang.annotation.ElementType.TYPE;
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Defines a named identifier generator, an instance of the interface
|
* Defines a named identifier generator, usually an instance of the interface
|
||||||
* {@link org.hibernate.id.IdentifierGenerator}. This allows the use of
|
* {@link org.hibernate.id.IdentifierGenerator}. This allows the use of custom
|
||||||
* custom identifier generation strategies beyond those provided by the
|
* identifier generation strategies beyond those provided by the four basic
|
||||||
* four basic JPA-defined {@linkplain jakarta.persistence.GenerationType
|
* JPA-defined {@linkplain jakarta.persistence.GenerationType generation types}.
|
||||||
* generation types}.
|
|
||||||
* <p>
|
* <p>
|
||||||
* A named generator may be associated with an entity class by:
|
* A named generator may be associated with an entity class by:
|
||||||
* <ul>
|
* <ul>
|
||||||
|
@ -74,17 +73,17 @@ public @interface GenericGenerator {
|
||||||
*/
|
*/
|
||||||
String name();
|
String name();
|
||||||
/**
|
/**
|
||||||
* The type of identifier generator, a class implementing {@link InMemoryGenerator}
|
* The type of identifier generator, a class implementing {@link Generator}
|
||||||
* or, more commonly, {@link org.hibernate.id.IdentifierGenerator}.
|
* or, more commonly, {@link org.hibernate.id.IdentifierGenerator}.
|
||||||
*
|
*
|
||||||
* @since 6.2
|
* @since 6.2
|
||||||
*/
|
*/
|
||||||
Class<? extends InMemoryGenerator> type() default InMemoryGenerator.class;
|
Class<? extends Generator> type() default Generator.class;
|
||||||
/**
|
/**
|
||||||
* The type of identifier generator, the name of either:
|
* The type of identifier generator, the name of either:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>a built-in Hibernate id generator, or
|
* <li>a built-in Hibernate id generator, or
|
||||||
* <li>a custom class implementing {@link InMemoryGenerator}, or, more commonly,
|
* <li>a custom class implementing {@link Generator}, or, more commonly,
|
||||||
* {@link org.hibernate.id.IdentifierGenerator}.
|
* {@link org.hibernate.id.IdentifierGenerator}.
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
|
|
@ -81,6 +81,7 @@ import org.hibernate.cfg.annotations.QueryBinder;
|
||||||
import org.hibernate.dialect.TimeZoneSupport;
|
import org.hibernate.dialect.TimeZoneSupport;
|
||||||
import org.hibernate.engine.OptimisticLockStyle;
|
import org.hibernate.engine.OptimisticLockStyle;
|
||||||
import org.hibernate.engine.spi.FilterDefinition;
|
import org.hibernate.engine.spi.FilterDefinition;
|
||||||
|
import org.hibernate.generator.Generator;
|
||||||
import org.hibernate.internal.CoreMessageLogger;
|
import org.hibernate.internal.CoreMessageLogger;
|
||||||
import org.hibernate.internal.util.GenericsHelper;
|
import org.hibernate.internal.util.GenericsHelper;
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
|
@ -98,7 +99,6 @@ import org.hibernate.property.access.internal.PropertyAccessStrategyMixedImpl;
|
||||||
import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
import org.hibernate.property.access.spi.PropertyAccessStrategy;
|
||||||
import org.hibernate.resource.beans.spi.ManagedBean;
|
import org.hibernate.resource.beans.spi.ManagedBean;
|
||||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||||
import org.hibernate.generator.InMemoryGenerator;
|
|
||||||
import org.hibernate.type.BasicType;
|
import org.hibernate.type.BasicType;
|
||||||
import org.hibernate.type.CustomType;
|
import org.hibernate.type.CustomType;
|
||||||
import org.hibernate.type.descriptor.java.BasicJavaType;
|
import org.hibernate.type.descriptor.java.BasicJavaType;
|
||||||
|
@ -489,7 +489,7 @@ public final class AnnotationBinder {
|
||||||
else if ( generatorAnnotation instanceof GenericGenerator ) {
|
else if ( generatorAnnotation instanceof GenericGenerator ) {
|
||||||
final GenericGenerator genericGenerator = (GenericGenerator) generatorAnnotation;
|
final GenericGenerator genericGenerator = (GenericGenerator) generatorAnnotation;
|
||||||
definitionBuilder.setName( genericGenerator.name() );
|
definitionBuilder.setName( genericGenerator.name() );
|
||||||
final String strategy = genericGenerator.type().equals(InMemoryGenerator.class)
|
final String strategy = genericGenerator.type().equals(Generator.class)
|
||||||
? genericGenerator.strategy()
|
? genericGenerator.strategy()
|
||||||
: genericGenerator.type().getName();
|
: genericGenerator.type().getName();
|
||||||
definitionBuilder.setStrategy( strategy );
|
definitionBuilder.setStrategy( strategy );
|
||||||
|
|
|
@ -7,7 +7,9 @@
|
||||||
package org.hibernate.generator;
|
package org.hibernate.generator;
|
||||||
|
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
|
import org.hibernate.id.insert.BasicSelectingDelegate;
|
||||||
|
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A value generated by the database might be generated implicitly, by a trigger, or using
|
* A value generated by the database might be generated implicitly, by a trigger, or using
|
||||||
|
@ -69,18 +71,15 @@ public interface InDatabaseGenerator extends Generator {
|
||||||
String[] getReferencedColumnValues(Dialect dialect);
|
String[] getReferencedColumnValues(Dialect dialect);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The name of a property of the entity which may be used to locate the just-{@code insert}ed
|
* The {@link InsertGeneratedIdentifierDelegate} used to retrieve the generates value if this
|
||||||
* row containing the generated value. Of course, the columns mapped by this property should
|
* object is an identifier generator.
|
||||||
* form a unique key of the entity.
|
|
||||||
* <p>
|
* <p>
|
||||||
* This is ignored by {@link org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor},
|
* This is ignored by {@link org.hibernate.metamodel.mapping.internal.GeneratedValuesProcessor},
|
||||||
* which handles multiple generators at once. This method arguably breaks the separation of
|
* which handles multiple generators at once. This method arguably breaks the separation of
|
||||||
* concerns between the generator and the coordinating code.
|
* concerns between the generator and the coordinating code.
|
||||||
*
|
|
||||||
* @see org.hibernate.id.SelectGenerator
|
|
||||||
*/
|
*/
|
||||||
default String getUniqueKeyPropertyName(EntityPersister persister) {
|
default InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate(PostInsertIdentityPersister persister) {
|
||||||
return null;
|
return new BasicSelectingDelegate( persister, persister.getFactory().getJdbcServices().getDialect() );
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean generatedByDatabase() {
|
default boolean generatedByDatabase() {
|
||||||
|
|
|
@ -9,6 +9,9 @@ package org.hibernate.id;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.id.factory.spi.StandardGenerator;
|
import org.hibernate.id.factory.spi.StandardGenerator;
|
||||||
import org.hibernate.generator.InDatabaseGenerator;
|
import org.hibernate.generator.InDatabaseGenerator;
|
||||||
|
import org.hibernate.id.insert.BasicSelectingDelegate;
|
||||||
|
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||||
|
import org.hibernate.id.insert.InsertReturningDelegate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An {@link InDatabaseGenerator} that handles {@code IDENTITY}/"autoincrement" columns
|
* An {@link InDatabaseGenerator} that handles {@code IDENTITY}/"autoincrement" columns
|
||||||
|
@ -16,11 +19,23 @@ import org.hibernate.generator.InDatabaseGenerator;
|
||||||
* <p>
|
* <p>
|
||||||
* Delegates to the {@link org.hibernate.dialect.identity.IdentityColumnSupport} provided
|
* Delegates to the {@link org.hibernate.dialect.identity.IdentityColumnSupport} provided
|
||||||
* by the {@linkplain Dialect#getIdentityColumnSupport() dialect}.
|
* by the {@linkplain Dialect#getIdentityColumnSupport() dialect}.
|
||||||
|
* <p>
|
||||||
|
* The actual work involved in retrieving the primary key value is the job of a
|
||||||
|
* {@link org.hibernate.id.insert.InsertGeneratedIdentifierDelegate}, either:
|
||||||
|
* <ul>
|
||||||
|
* <li>a {@link org.hibernate.id.insert.GetGeneratedKeysDelegate},
|
||||||
|
* <li>an {@link org.hibernate.id.insert.InsertReturningDelegate}, or a
|
||||||
|
* <li>a {@link org.hibernate.id.insert.BasicSelectingDelegate}.
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @see org.hibernate.dialect.identity.IdentityColumnSupport
|
||||||
|
* @see org.hibernate.id.insert.InsertGeneratedIdentifierDelegate
|
||||||
*
|
*
|
||||||
* @author Christoph Sturm
|
* @author Christoph Sturm
|
||||||
*/
|
*/
|
||||||
public class IdentityGenerator
|
public class IdentityGenerator
|
||||||
implements PostInsertIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, StandardGenerator {
|
implements PostInsertIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, StandardGenerator {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean referenceColumnsInSql(Dialect dialect) {
|
public boolean referenceColumnsInSql(Dialect dialect) {
|
||||||
return dialect.getIdentityColumnSupport().hasIdentityInsertKeyword();
|
return dialect.getIdentityColumnSupport().hasIdentityInsertKeyword();
|
||||||
|
@ -30,4 +45,18 @@ public class IdentityGenerator
|
||||||
public String[] getReferencedColumnValues(Dialect dialect) {
|
public String[] getReferencedColumnValues(Dialect dialect) {
|
||||||
return new String[] { dialect.getIdentityColumnSupport().getIdentityInsertString() };
|
return new String[] { dialect.getIdentityColumnSupport().getIdentityInsertString() };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate(PostInsertIdentityPersister persister) {
|
||||||
|
Dialect dialect = persister.getFactory().getJdbcServices().getDialect();
|
||||||
|
if ( persister.getFactory().getSessionFactoryOptions().isGetGeneratedKeysEnabled() ) {
|
||||||
|
return dialect.getIdentityColumnSupport().buildGetGeneratedKeysDelegate( persister, dialect );
|
||||||
|
}
|
||||||
|
else if ( dialect.getIdentityColumnSupport().supportsInsertSelectIdentity() ) {
|
||||||
|
return new InsertReturningDelegate( persister, dialect );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new BasicSelectingDelegate( persister, dialect );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ import java.util.Properties;
|
||||||
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
|
import static org.hibernate.generator.EventTypeSets.INSERT_ONLY;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The counterpart of {@link IdentifierGenerator} for values generated by the database.
|
* The counterpart to {@link IdentifierGenerator} for values generated by the database.
|
||||||
* This interface is no longer the only way to handle database-generate identifiers.
|
* This interface is no longer the only way to handle database-generate identifiers.
|
||||||
* Any {@link InDatabaseGenerator} with timing {@link EventTypeSets#INSERT_ONLY} may now
|
* Any {@link InDatabaseGenerator} with timing {@link EventTypeSets#INSERT_ONLY} may now
|
||||||
* be used.
|
* be used.
|
||||||
|
|
|
@ -11,14 +11,16 @@ import java.util.Properties;
|
||||||
import org.hibernate.dialect.Dialect;
|
import org.hibernate.dialect.Dialect;
|
||||||
import org.hibernate.generator.InDatabaseGenerator;
|
import org.hibernate.generator.InDatabaseGenerator;
|
||||||
import org.hibernate.id.factory.spi.StandardGenerator;
|
import org.hibernate.id.factory.spi.StandardGenerator;
|
||||||
|
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||||
|
import org.hibernate.id.insert.UniqueKeySelectingDelegate;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.service.ServiceRegistry;
|
import org.hibernate.service.ServiceRegistry;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A generator that {@code select}s the just-{@code insert}ed row to determine the
|
* A generator that {@code select}s the just-{@code insert}ed row to determine the
|
||||||
* column value assigned by the database. The correct row is located
|
* column value assigned by the database. The correct row is located using a unique
|
||||||
* using a unique key of the entity, either:
|
* key of the entity, either:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>the mapped {@linkplain org.hibernate.annotations.NaturalId} of the entity, or
|
* <li>the mapped {@linkplain org.hibernate.annotations.NaturalId} of the entity, or
|
||||||
* <li>a property specified using the parameter named {@code "key"}.
|
* <li>a property specified using the parameter named {@code "key"}.
|
||||||
|
@ -26,11 +28,32 @@ import org.hibernate.type.Type;
|
||||||
* The second approach is provided for backward compatibility with older versions of
|
* The second approach is provided for backward compatibility with older versions of
|
||||||
* Hibernate.
|
* Hibernate.
|
||||||
* <p>
|
* <p>
|
||||||
|
* This generator is intended for use with primary keys assigned by a database trigger
|
||||||
|
* or something similar, for example:
|
||||||
|
* <pre>{@code
|
||||||
|
* @Entity @Table(name="TableWithPKAssignedByTrigger")
|
||||||
|
* @GenericGenerator(name = "triggered", type = SelectGenerator.class)
|
||||||
|
* public class TriggeredEntity {
|
||||||
|
* @Id @GeneratedValue(generator = "triggered")
|
||||||
|
* private Long id;
|
||||||
|
*
|
||||||
|
* @NaturalId
|
||||||
|
* private String name;
|
||||||
|
*
|
||||||
|
* ...
|
||||||
|
* }
|
||||||
|
* }</pre>
|
||||||
|
* For tables with identity/autoincrement columns, use {@link IdentityGenerator}.
|
||||||
|
* <p>
|
||||||
|
* The actual work involved in retrieving the primary key value is the job of
|
||||||
|
* {@link org.hibernate.id.insert.UniqueKeySelectingDelegate}.
|
||||||
|
* <p>
|
||||||
* Arguably, this class breaks the natural separation of responsibility between the
|
* Arguably, this class breaks the natural separation of responsibility between the
|
||||||
* {@linkplain InDatabaseGenerator generator} and the coordinating
|
* {@linkplain InDatabaseGenerator generator} and the coordinating code, since its
|
||||||
* code, since it's role is to specify how the generated value is <em>retrieved</em>.
|
* role is to specify how the generated value is <em>retrieved</em>.
|
||||||
*
|
*
|
||||||
* @see org.hibernate.annotations.NaturalId
|
* @see org.hibernate.annotations.NaturalId
|
||||||
|
* @see org.hibernate.id.insert.UniqueKeySelectingDelegate
|
||||||
*
|
*
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
|
@ -43,8 +66,12 @@ public class SelectGenerator
|
||||||
uniqueKeyPropertyName = parameters.getProperty( "key" );
|
uniqueKeyPropertyName = parameters.getProperty( "key" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public String getUniqueKeyPropertyName(EntityPersister persister) {
|
* The name of a property of the entity which may be used to locate the just-{@code insert}ed
|
||||||
|
* row containing the generated value. Of course, the columns mapped by this property should
|
||||||
|
* form a unique key of the entity.
|
||||||
|
*/
|
||||||
|
protected String getUniqueKeyPropertyName(EntityPersister persister) {
|
||||||
if ( uniqueKeyPropertyName != null ) {
|
if ( uniqueKeyPropertyName != null ) {
|
||||||
return uniqueKeyPropertyName;
|
return uniqueKeyPropertyName;
|
||||||
}
|
}
|
||||||
|
@ -70,6 +97,12 @@ public class SelectGenerator
|
||||||
return persister.getPropertyNames()[naturalIdPropertyIndices[0]];
|
return persister.getPropertyNames()[naturalIdPropertyIndices[0]];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate(PostInsertIdentityPersister persister) {
|
||||||
|
Dialect dialect = persister.getFactory().getJdbcServices().getDialect();
|
||||||
|
return new UniqueKeySelectingDelegate( persister, dialect, getUniqueKeyPropertyName( persister ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean referenceColumnsInSql(Dialect dialect) {
|
public boolean referenceColumnsInSql(Dialect dialect) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -13,14 +13,13 @@ import org.hibernate.engine.jdbc.mutation.JdbcValueBindings;
|
||||||
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
import org.hibernate.engine.jdbc.mutation.group.PreparedStatementDetails;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.generator.InDatabaseGenerator;
|
|
||||||
import org.hibernate.jdbc.Expectation;
|
import org.hibernate.jdbc.Expectation;
|
||||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||||
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each implementation defines a strategy for retrieving a primary key
|
* Each implementation defines a strategy for retrieving a primary key
|
||||||
* {@linkplain InDatabaseGenerator generated by
|
* {@linkplain org.hibernate.generator.InDatabaseGenerator generated by
|
||||||
* the database} from the database after execution of an {@code insert}
|
* the database} from the database after execution of an {@code insert}
|
||||||
* statement. The generated primary key is usually an {@code IDENTITY}
|
* statement. The generated primary key is usually an {@code IDENTITY}
|
||||||
* column, but in principle it might be something else, for example,
|
* column, but in principle it might be something else, for example,
|
||||||
|
@ -32,9 +31,9 @@ import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
|
||||||
* <li>retrieving the generated identifier value using JDBC.
|
* <li>retrieving the generated identifier value using JDBC.
|
||||||
* </ul>
|
* </ul>
|
||||||
* The implementation should be written to handle any instance of
|
* The implementation should be written to handle any instance of
|
||||||
* {@link InDatabaseGenerator}.
|
* {@link org.hibernate.generator.InDatabaseGenerator}.
|
||||||
*
|
*
|
||||||
* @see InDatabaseGenerator
|
* @see org.hibernate.generator.InDatabaseGenerator
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -2743,29 +2743,6 @@ public abstract class AbstractEntityPersister
|
||||||
return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGeneratedByDatabase();
|
return includeProperty[getVersionProperty()] || entityMetamodel.isVersionGeneratedByDatabase();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean useGetGeneratedKeys() {
|
|
||||||
return getFactory().getSessionFactoryOptions().isGetGeneratedKeysEnabled();
|
|
||||||
}
|
|
||||||
|
|
||||||
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate() {
|
|
||||||
Dialect dialect = getFactory().getJdbcServices().getDialect();
|
|
||||||
if ( useGetGeneratedKeys() ) {
|
|
||||||
return dialect.getIdentityColumnSupport().buildGetGeneratedKeysDelegate(this, dialect );
|
|
||||||
}
|
|
||||||
else if ( dialect.getIdentityColumnSupport().supportsInsertSelectIdentity() ) {
|
|
||||||
return new InsertReturningDelegate(this, dialect );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return new BasicSelectingDelegate(this, dialect );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegateForProperty(String uniqueKeyPropertyName) {
|
|
||||||
Dialect dialect = getFactory().getJdbcServices().getDialect();
|
|
||||||
return new UniqueKeySelectingDelegate( this, dialect, uniqueKeyPropertyName );
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIdentitySelectString() {
|
public String getIdentitySelectString() {
|
||||||
//TODO: cache this in an instvar
|
//TODO: cache this in an instvar
|
||||||
|
@ -3082,10 +3059,7 @@ public abstract class AbstractEntityPersister
|
||||||
private void doLateInit() {
|
private void doLateInit() {
|
||||||
if ( isIdentifierAssignedByInsert() ) {
|
if ( isIdentifierAssignedByInsert() ) {
|
||||||
final InDatabaseGenerator generator = (InDatabaseGenerator) getGenerator();
|
final InDatabaseGenerator generator = (InDatabaseGenerator) getGenerator();
|
||||||
final String uniqueKeyPropertyName = generator.getUniqueKeyPropertyName(this);
|
identityDelegate = generator.getGeneratedIdentifierDelegate( this );
|
||||||
identityDelegate = uniqueKeyPropertyName == null
|
|
||||||
? getGeneratedIdentifierDelegate()
|
|
||||||
: getGeneratedIdentifierDelegateForProperty( uniqueKeyPropertyName );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tableMappings = buildTableMappings();
|
tableMappings = buildTableMappings();
|
||||||
|
|
|
@ -1015,14 +1015,6 @@ public interface EntityPersister extends EntityMappingType, RootTableGroupProduc
|
||||||
|
|
||||||
boolean canUseReferenceCacheEntries();
|
boolean canUseReferenceCacheEntries();
|
||||||
|
|
||||||
default InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegate() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
default InsertGeneratedIdentifierDelegate getGeneratedIdentifierDelegateForProperty(String uniqueKeyPropertyName) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property name of the "special" identifier property in HQL
|
* The property name of the "special" identifier property in HQL
|
||||||
*
|
*
|
||||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.generator.EventType;
|
import org.hibernate.generator.EventType;
|
||||||
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||||
import org.hibernate.id.OptimizableGenerator;
|
import org.hibernate.id.OptimizableGenerator;
|
||||||
|
import org.hibernate.id.PostInsertIdentityPersister;
|
||||||
import org.hibernate.id.enhanced.Optimizer;
|
import org.hibernate.id.enhanced.Optimizer;
|
||||||
import org.hibernate.id.insert.Binder;
|
import org.hibernate.id.insert.Binder;
|
||||||
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
|
||||||
|
@ -559,10 +560,8 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
|
||||||
|
|
||||||
if ( generator.generatedByDatabase() ) {
|
if ( generator.generatedByDatabase() ) {
|
||||||
final InDatabaseGenerator databaseGenerator = (InDatabaseGenerator) generator;
|
final InDatabaseGenerator databaseGenerator = (InDatabaseGenerator) generator;
|
||||||
final String uniqueKeyPropertyName = databaseGenerator.getUniqueKeyPropertyName( entityPersister );
|
final InsertGeneratedIdentifierDelegate identifierDelegate =
|
||||||
final InsertGeneratedIdentifierDelegate identifierDelegate = uniqueKeyPropertyName == null
|
databaseGenerator.getGeneratedIdentifierDelegate( (PostInsertIdentityPersister) entityPersister );
|
||||||
? entityPersister.getGeneratedIdentifierDelegate()
|
|
||||||
: entityPersister.getGeneratedIdentifierDelegateForProperty( uniqueKeyPropertyName );
|
|
||||||
final String finalSql = identifierDelegate.prepareIdentifierGeneratingInsert( jdbcInsert.getSqlString() );
|
final String finalSql = identifierDelegate.prepareIdentifierGeneratingInsert( jdbcInsert.getSqlString() );
|
||||||
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
|
||||||
final ValueBinder jdbcValueBinder = identifierMapping.getJdbcMapping().getJdbcValueBinder();
|
final ValueBinder jdbcValueBinder = identifierMapping.getJdbcMapping().getJdbcValueBinder();
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<?xml version="1.0"?>
|
||||||
|
<!--
|
||||||
|
~ 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>.
|
||||||
|
-->
|
||||||
|
<!DOCTYPE hibernate-mapping PUBLIC
|
||||||
|
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
|
||||||
|
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
|
||||||
|
|
||||||
|
<hibernate-mapping package="org.hibernate.orm.test.generatedkeys.select" default-access="field">
|
||||||
|
|
||||||
|
<database-object>
|
||||||
|
<create>
|
||||||
|
<![CDATA[CREATE OR REPLACE TRIGGER t_i_my_entity
|
||||||
|
BEFORE INSERT ON my_entity
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
select nvl( max(id), 0 ) + 1
|
||||||
|
into :new.id
|
||||||
|
from my_entity;
|
||||||
|
END;]]>
|
||||||
|
</create>
|
||||||
|
<drop>
|
||||||
|
<![CDATA[DROP TRIGGER t_i_my_entity]]>
|
||||||
|
</drop>
|
||||||
|
<dialect-scope name="org.hibernate.dialect.OracleDialect"/>
|
||||||
|
</database-object>
|
||||||
|
|
||||||
|
</hibernate-mapping>
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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.generatedkeys.selectannotated;
|
||||||
|
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.GeneratedValue;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.Table;
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
|
import org.hibernate.annotations.NaturalId;
|
||||||
|
import org.hibernate.id.SelectGenerator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:steve@hibernate.org">Steve Ebersole </a>
|
||||||
|
*/
|
||||||
|
@Entity @Table(name="my_entity")
|
||||||
|
@GenericGenerator(name = "triggered", type = SelectGenerator.class)
|
||||||
|
public class MyEntity {
|
||||||
|
@Id @GeneratedValue(generator = "triggered")
|
||||||
|
private Long id;
|
||||||
|
|
||||||
|
@NaturalId
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public MyEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public MyEntity(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* 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.generatedkeys.selectannotated;
|
||||||
|
|
||||||
|
import org.hibernate.dialect.OracleDialect;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.JiraKey;
|
||||||
|
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.tool.hbm2ddl.SchemaExport;
|
||||||
|
import org.hibernate.tool.schema.TargetType;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.util.EnumSet;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
* @author Marco Belladelli
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = MyEntity.class,
|
||||||
|
xmlMappings = "org/hibernate/orm/test/generatedkeys/selectannotated/MyEntity.hbm.xml"
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@RequiresDialect(value = OracleDialect.class)
|
||||||
|
public class SelectGeneratorTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testJDBC3GetGeneratedKeysSupportOnOracle(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
MyEntity e = new MyEntity( "entity-1" );
|
||||||
|
session.persist( e );
|
||||||
|
|
||||||
|
// this insert should happen immediately!
|
||||||
|
assertEquals( Long.valueOf( 1L ), e.getId(), "id not generated through forced insertion" );
|
||||||
|
|
||||||
|
session.remove( e );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@JiraKey("HHH-15900")
|
||||||
|
public void testGeneratedKeyNotIdentityColumn(SessionFactoryScope scope) throws IOException {
|
||||||
|
File output = File.createTempFile( "schema_export", ".sql" );
|
||||||
|
output.deleteOnExit();
|
||||||
|
|
||||||
|
final SchemaExport schemaExport = new SchemaExport();
|
||||||
|
schemaExport.setOutputFile( output.getAbsolutePath() );
|
||||||
|
schemaExport.execute(
|
||||||
|
EnumSet.of( TargetType.SCRIPT ),
|
||||||
|
SchemaExport.Action.CREATE,
|
||||||
|
scope.getMetadataImplementor()
|
||||||
|
);
|
||||||
|
|
||||||
|
String fileContent = new String( Files.readAllBytes( output.toPath() ) );
|
||||||
|
assertFalse( fileContent.toLowerCase().contains( "identity" ), "Column was generated as identity" );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue