remove ancient limitation that allowed only one property as UK for 'select' id generator
This commit is contained in:
parent
d30bf092aa
commit
f3e31fe427
|
@ -15,7 +15,7 @@ import org.hibernate.id.insert.InsertReturningDelegate;
|
||||||
import org.hibernate.id.insert.UniqueKeySelectingDelegate;
|
import org.hibernate.id.insert.UniqueKeySelectingDelegate;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
import static org.hibernate.generator.internal.NaturalIdHelper.getNaturalIdPropertyName;
|
import static org.hibernate.generator.internal.NaturalIdHelper.getNaturalIdPropertyNames;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -116,7 +116,7 @@ public interface InDatabaseGenerator extends Generator {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// let's just hope the entity has a @NaturalId!
|
// let's just hope the entity has a @NaturalId!
|
||||||
return new UniqueKeySelectingDelegate( persister, dialect, getUniqueKeyPropertyName( persister ) );
|
return new UniqueKeySelectingDelegate( persister, dialect, getUniqueKeyPropertyNames( persister ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -129,8 +129,8 @@ public interface InDatabaseGenerator extends Generator {
|
||||||
* property, if there is one.
|
* property, if there is one.
|
||||||
*/
|
*/
|
||||||
@Incubating
|
@Incubating
|
||||||
default String getUniqueKeyPropertyName(EntityPersister persister) {
|
default String[] getUniqueKeyPropertyNames(EntityPersister persister) {
|
||||||
return getNaturalIdPropertyName( persister );
|
return getNaturalIdPropertyNames( persister );
|
||||||
}
|
}
|
||||||
|
|
||||||
default boolean generatedByDatabase() {
|
default boolean generatedByDatabase() {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
package org.hibernate.generator.internal;
|
package org.hibernate.generator.internal;
|
||||||
|
|
||||||
import org.hibernate.AssertionFailure;
|
import org.hibernate.AssertionFailure;
|
||||||
import org.hibernate.Session;
|
|
||||||
import org.hibernate.annotations.CreationTimestamp;
|
import org.hibernate.annotations.CreationTimestamp;
|
||||||
import org.hibernate.annotations.CurrentTimestamp;
|
import org.hibernate.annotations.CurrentTimestamp;
|
||||||
import org.hibernate.annotations.SourceType;
|
import org.hibernate.annotations.SourceType;
|
||||||
|
|
|
@ -9,27 +9,25 @@ package org.hibernate.generator.internal;
|
||||||
import org.hibernate.id.IdentifierGenerationException;
|
import org.hibernate.id.IdentifierGenerationException;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Gavin King
|
||||||
|
*/
|
||||||
public class NaturalIdHelper {
|
public class NaturalIdHelper {
|
||||||
public static String getNaturalIdPropertyName(EntityPersister persister) {
|
public static String[] getNaturalIdPropertyNames(EntityPersister persister) {
|
||||||
int[] naturalIdPropertyIndices = persister.getNaturalIdentifierProperties();
|
final int[] naturalIdPropertyIndices = persister.getNaturalIdentifierProperties();
|
||||||
if ( naturalIdPropertyIndices == null ) {
|
if ( naturalIdPropertyIndices == null ) {
|
||||||
throw new IdentifierGenerationException(
|
throw new IdentifierGenerationException( "entity '" + persister.getEntityName()
|
||||||
"no natural-id property defined; " +
|
+ "' has no '@NaturalId' property" );
|
||||||
"need to specify [key] in generator parameters"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if ( naturalIdPropertyIndices.length > 1 ) {
|
|
||||||
throw new IdentifierGenerationException(
|
|
||||||
"generator does not currently support composite natural-id properties;" +
|
|
||||||
" need to specify [key] in generator parameters"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if ( persister.getEntityMetamodel().isNaturalIdentifierInsertGenerated() ) {
|
if ( persister.getEntityMetamodel().isNaturalIdentifierInsertGenerated() ) {
|
||||||
throw new IdentifierGenerationException(
|
throw new IdentifierGenerationException( "entity '" + persister.getEntityName()
|
||||||
"natural-id also defined as insert-generated; " +
|
+ "' has a '@NaturalId' property which is also defined as insert-generated" );
|
||||||
"need to specify [key] in generator parameters"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return persister.getPropertyNames()[naturalIdPropertyIndices[0]];
|
final String[] allPropertyNames = persister.getPropertyNames();
|
||||||
|
final String[] propertyNames = new String[naturalIdPropertyIndices.length];
|
||||||
|
for ( int i = 0; i < naturalIdPropertyIndices.length; i++ ) {
|
||||||
|
propertyNames[i] = allPropertyNames[naturalIdPropertyIndices[i]];
|
||||||
|
}
|
||||||
|
return propertyNames;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,14 +18,30 @@ import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
||||||
public interface PostInsertIdentityPersister extends EntityPersister, EntityMutationTarget {
|
public interface PostInsertIdentityPersister extends EntityPersister, EntityMutationTarget {
|
||||||
/**
|
/**
|
||||||
* Get a SQL select string that performs a select based on a unique
|
* Get a SQL select string that performs a select based on a unique
|
||||||
* key determined by the given property name).
|
* key determined by the given property name.
|
||||||
*
|
*
|
||||||
* @param propertyName The name of the property which maps to the
|
* @param propertyName The name of the property which maps to the
|
||||||
* column(s) to use in the select statement restriction.
|
* column(s) to use in the select statement restriction.
|
||||||
* @return The SQL select string
|
* @return The SQL select string
|
||||||
*/
|
*/
|
||||||
String getSelectByUniqueKeyString(String propertyName);
|
String getSelectByUniqueKeyString(String propertyName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a SQL select string that performs a select based on a unique
|
||||||
|
* key determined by the given property names.
|
||||||
|
*
|
||||||
|
* @param propertyNames The names of the properties which maps to the
|
||||||
|
* column(s) to use in the select statement restriction.
|
||||||
|
* @return The SQL select string
|
||||||
|
*/
|
||||||
|
default String getSelectByUniqueKeyString(String[] propertyNames) {
|
||||||
|
// default impl only for backward compatibility
|
||||||
|
if ( propertyNames.length > 1 ) {
|
||||||
|
throw new IllegalArgumentException( "support for multiple properties not implemented" );
|
||||||
|
}
|
||||||
|
return getSelectByUniqueKeyString( propertyNames[0] );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the database-specific SQL command to retrieve the last
|
* Get the database-specific SQL command to retrieve the last
|
||||||
* generated IDENTITY value.
|
* generated IDENTITY value.
|
||||||
|
|
|
@ -15,7 +15,7 @@ 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;
|
||||||
|
|
||||||
import static org.hibernate.generator.internal.NaturalIdHelper.getNaturalIdPropertyName;
|
import static org.hibernate.generator.internal.NaturalIdHelper.getNaturalIdPropertyNames;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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
|
||||||
|
@ -82,10 +82,10 @@ public class SelectGenerator
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getUniqueKeyPropertyName(EntityPersister persister) {
|
public String[] getUniqueKeyPropertyNames(EntityPersister persister) {
|
||||||
return uniqueKeyPropertyName != null
|
return uniqueKeyPropertyName != null
|
||||||
? uniqueKeyPropertyName
|
? new String[] { uniqueKeyPropertyName }
|
||||||
: getNaturalIdPropertyName( persister );
|
: getNaturalIdPropertyNames( persister );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -22,25 +22,30 @@ import java.sql.SQLException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Uses a unique key of the inserted entity to locate the newly inserted row.
|
* Uses a unique key of the inserted entity to locate the newly inserted row.
|
||||||
|
*
|
||||||
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
||||||
private final PostInsertIdentityPersister persister;
|
private final PostInsertIdentityPersister persister;
|
||||||
private final Dialect dialect;
|
private final Dialect dialect;
|
||||||
|
|
||||||
private final String uniqueKeyPropertyName;
|
private final String[] uniqueKeyPropertyNames;
|
||||||
private final Type uniqueKeyType;
|
private final Type[] uniqueKeyTypes;
|
||||||
|
|
||||||
private final String idSelectString;
|
private final String idSelectString;
|
||||||
|
|
||||||
public UniqueKeySelectingDelegate(PostInsertIdentityPersister persister, Dialect dialect, String uniqueKeyPropertyName) {
|
public UniqueKeySelectingDelegate(PostInsertIdentityPersister persister, Dialect dialect, String[] uniqueKeyPropertyNames) {
|
||||||
super( persister );
|
super( persister );
|
||||||
|
|
||||||
this.persister = persister;
|
this.persister = persister;
|
||||||
this.dialect = dialect;
|
this.dialect = dialect;
|
||||||
this.uniqueKeyPropertyName = uniqueKeyPropertyName;
|
this.uniqueKeyPropertyNames = uniqueKeyPropertyNames;
|
||||||
|
|
||||||
idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName );
|
idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyNames );
|
||||||
uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName );
|
uniqueKeyTypes = new Type[ uniqueKeyPropertyNames.length ];
|
||||||
|
for (int i = 0; i < uniqueKeyPropertyNames.length; i++ ) {
|
||||||
|
uniqueKeyTypes[i] = persister.getPropertyType( uniqueKeyPropertyNames[i] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected String getSelectSQL() {
|
protected String getSelectSQL() {
|
||||||
|
@ -62,6 +67,10 @@ public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
||||||
|
|
||||||
protected void bindParameters(Object entity, PreparedStatement ps, SharedSessionContractImplementor session)
|
protected void bindParameters(Object entity, PreparedStatement ps, SharedSessionContractImplementor session)
|
||||||
throws SQLException {
|
throws SQLException {
|
||||||
uniqueKeyType.nullSafeSet( ps, persister.getPropertyValue( entity, uniqueKeyPropertyName ), 1, session );
|
int index = 1;
|
||||||
|
for ( int i = 0; i < uniqueKeyPropertyNames.length; i++ ) {
|
||||||
|
uniqueKeyTypes[i].nullSafeSet( ps, persister.getPropertyValue( entity, uniqueKeyPropertyNames[i] ), index, session );
|
||||||
|
index += uniqueKeyTypes[i].getColumnSpan( session.getFactory() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2756,11 +2756,19 @@ public abstract class AbstractEntityPersister
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getSelectByUniqueKeyString(String propertyName) {
|
public String getSelectByUniqueKeyString(String propertyName) {
|
||||||
return new SimpleSelect( getFactory().getJdbcServices().getDialect() )
|
return getSelectByUniqueKeyString( new String[] { propertyName } );
|
||||||
.setTableName( getTableName( 0 ) )
|
}
|
||||||
.addColumns( getKeyColumns( 0 ) )
|
|
||||||
.addCondition( getPropertyColumnNames( propertyName ), "=?" )
|
@Override
|
||||||
.toStatementString();
|
public String getSelectByUniqueKeyString(String[] propertyNames) {
|
||||||
|
final SimpleSelect select =
|
||||||
|
new SimpleSelect( getFactory().getJdbcServices().getDialect() )
|
||||||
|
.setTableName( getTableName(0) )
|
||||||
|
.addColumns( getKeyColumns(0) );
|
||||||
|
for ( int i = 0; i < propertyNames.length; i++ ) {
|
||||||
|
select.addCondition( getPropertyColumnNames( propertyNames[i] ), "= ?" );
|
||||||
|
}
|
||||||
|
return select.toStatementString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -672,19 +672,21 @@ public class EntityMetamodel implements Serializable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return {@code true} if one of the properties belonging to the natural id
|
||||||
|
* is generated during the execution of an {@code insert} statement
|
||||||
|
*/
|
||||||
public boolean isNaturalIdentifierInsertGenerated() {
|
public boolean isNaturalIdentifierInsertGenerated() {
|
||||||
// the intention is for this call to replace the usage of the old ValueInclusion stuff (as exposed from
|
if ( naturalIdPropertyNumbers.length == 0 ) {
|
||||||
// persister) in SelectGenerator to determine if it is safe to use the natural identifier to find the
|
|
||||||
// insert-generated identifier. That wont work if the natural-id is also insert-generated.
|
|
||||||
//
|
|
||||||
// Assumptions:
|
|
||||||
// * That code checks that there is a natural identifier before making this call, so we assume the same here
|
|
||||||
// * That code assumes a non-composite natural-id, so we assume the same here
|
|
||||||
if ( naturalIdPropertyNumbers.length < 1 ) {
|
|
||||||
throw new IllegalStateException( "entity does not have a natural id: " + name );
|
throw new IllegalStateException( "entity does not have a natural id: " + name );
|
||||||
}
|
}
|
||||||
final Generator strategy = generators[ naturalIdPropertyNumbers[0] ];
|
for ( int i = 0; i < naturalIdPropertyNumbers.length; i++ ) {
|
||||||
return strategy != null && strategy.generatesSometimes();
|
final Generator strategy = generators[ naturalIdPropertyNumbers[i] ];
|
||||||
|
if ( strategy != null && strategy.generatesOnInsert() && strategy.generatedOnExecute() ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isVersionGeneratedByDatabase() {
|
public boolean isVersionGeneratedByDatabase() {
|
||||||
|
|
Loading…
Reference in New Issue