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.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
|
||||
|
@ -116,7 +116,7 @@ public interface InDatabaseGenerator extends Generator {
|
|||
}
|
||||
else {
|
||||
// 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.
|
||||
*/
|
||||
@Incubating
|
||||
default String getUniqueKeyPropertyName(EntityPersister persister) {
|
||||
return getNaturalIdPropertyName( persister );
|
||||
default String[] getUniqueKeyPropertyNames(EntityPersister persister) {
|
||||
return getNaturalIdPropertyNames( persister );
|
||||
}
|
||||
|
||||
default boolean generatedByDatabase() {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.generator.internal;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.CreationTimestamp;
|
||||
import org.hibernate.annotations.CurrentTimestamp;
|
||||
import org.hibernate.annotations.SourceType;
|
||||
|
|
|
@ -9,27 +9,25 @@ package org.hibernate.generator.internal;
|
|||
import org.hibernate.id.IdentifierGenerationException;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
||||
/**
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class NaturalIdHelper {
|
||||
public static String getNaturalIdPropertyName(EntityPersister persister) {
|
||||
int[] naturalIdPropertyIndices = persister.getNaturalIdentifierProperties();
|
||||
public static String[] getNaturalIdPropertyNames(EntityPersister persister) {
|
||||
final int[] naturalIdPropertyIndices = persister.getNaturalIdentifierProperties();
|
||||
if ( naturalIdPropertyIndices == null ) {
|
||||
throw new IdentifierGenerationException(
|
||||
"no natural-id property defined; " +
|
||||
"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"
|
||||
);
|
||||
throw new IdentifierGenerationException( "entity '" + persister.getEntityName()
|
||||
+ "' has no '@NaturalId' property" );
|
||||
}
|
||||
if ( persister.getEntityMetamodel().isNaturalIdentifierInsertGenerated() ) {
|
||||
throw new IdentifierGenerationException(
|
||||
"natural-id also defined as insert-generated; " +
|
||||
"need to specify [key] in generator parameters"
|
||||
);
|
||||
throw new IdentifierGenerationException( "entity '" + persister.getEntityName()
|
||||
+ "' has a '@NaturalId' property which is also defined as insert-generated" );
|
||||
}
|
||||
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,7 +18,7 @@ import org.hibernate.persister.entity.mutation.EntityMutationTarget;
|
|||
public interface PostInsertIdentityPersister extends EntityPersister, EntityMutationTarget {
|
||||
/**
|
||||
* 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
|
||||
* column(s) to use in the select statement restriction.
|
||||
|
@ -26,6 +26,22 @@ public interface PostInsertIdentityPersister extends EntityPersister, EntityMuta
|
|||
*/
|
||||
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
|
||||
* generated IDENTITY value.
|
||||
|
|
|
@ -15,7 +15,7 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.service.ServiceRegistry;
|
||||
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
|
||||
|
@ -82,10 +82,10 @@ public class SelectGenerator
|
|||
}
|
||||
|
||||
@Override
|
||||
public String getUniqueKeyPropertyName(EntityPersister persister) {
|
||||
public String[] getUniqueKeyPropertyNames(EntityPersister persister) {
|
||||
return uniqueKeyPropertyName != null
|
||||
? uniqueKeyPropertyName
|
||||
: getNaturalIdPropertyName( persister );
|
||||
? new String[] { uniqueKeyPropertyName }
|
||||
: getNaturalIdPropertyNames( persister );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -22,25 +22,30 @@ import java.sql.SQLException;
|
|||
|
||||
/**
|
||||
* Uses a unique key of the inserted entity to locate the newly inserted row.
|
||||
*
|
||||
* @author Gavin King
|
||||
*/
|
||||
public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
||||
private final PostInsertIdentityPersister persister;
|
||||
private final Dialect dialect;
|
||||
|
||||
private final String uniqueKeyPropertyName;
|
||||
private final Type uniqueKeyType;
|
||||
private final String[] uniqueKeyPropertyNames;
|
||||
private final Type[] uniqueKeyTypes;
|
||||
|
||||
private final String idSelectString;
|
||||
|
||||
public UniqueKeySelectingDelegate(PostInsertIdentityPersister persister, Dialect dialect, String uniqueKeyPropertyName) {
|
||||
public UniqueKeySelectingDelegate(PostInsertIdentityPersister persister, Dialect dialect, String[] uniqueKeyPropertyNames) {
|
||||
super( persister );
|
||||
|
||||
this.persister = persister;
|
||||
this.dialect = dialect;
|
||||
this.uniqueKeyPropertyName = uniqueKeyPropertyName;
|
||||
this.uniqueKeyPropertyNames = uniqueKeyPropertyNames;
|
||||
|
||||
idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyName );
|
||||
uniqueKeyType = persister.getPropertyType( uniqueKeyPropertyName );
|
||||
idSelectString = persister.getSelectByUniqueKeyString( uniqueKeyPropertyNames );
|
||||
uniqueKeyTypes = new Type[ uniqueKeyPropertyNames.length ];
|
||||
for (int i = 0; i < uniqueKeyPropertyNames.length; i++ ) {
|
||||
uniqueKeyTypes[i] = persister.getPropertyType( uniqueKeyPropertyNames[i] );
|
||||
}
|
||||
}
|
||||
|
||||
protected String getSelectSQL() {
|
||||
|
@ -62,6 +67,10 @@ public class UniqueKeySelectingDelegate extends AbstractSelectingDelegate {
|
|||
|
||||
protected void bindParameters(Object entity, PreparedStatement ps, SharedSessionContractImplementor session)
|
||||
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
|
||||
public String getSelectByUniqueKeyString(String propertyName) {
|
||||
return new SimpleSelect( getFactory().getJdbcServices().getDialect() )
|
||||
return getSelectByUniqueKeyString( new String[] { propertyName } );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectByUniqueKeyString(String[] propertyNames) {
|
||||
final SimpleSelect select =
|
||||
new SimpleSelect( getFactory().getJdbcServices().getDialect() )
|
||||
.setTableName( getTableName(0) )
|
||||
.addColumns( getKeyColumns( 0 ) )
|
||||
.addCondition( getPropertyColumnNames( propertyName ), "=?" )
|
||||
.toStatementString();
|
||||
.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() {
|
||||
// the intention is for this call to replace the usage of the old ValueInclusion stuff (as exposed from
|
||||
// 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 ) {
|
||||
if ( naturalIdPropertyNumbers.length == 0 ) {
|
||||
throw new IllegalStateException( "entity does not have a natural id: " + name );
|
||||
}
|
||||
final Generator strategy = generators[ naturalIdPropertyNumbers[0] ];
|
||||
return strategy != null && strategy.generatesSometimes();
|
||||
for ( int i = 0; i < naturalIdPropertyNumbers.length; i++ ) {
|
||||
final Generator strategy = generators[ naturalIdPropertyNumbers[i] ];
|
||||
if ( strategy != null && strategy.generatesOnInsert() && strategy.generatedOnExecute() ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isVersionGeneratedByDatabase() {
|
||||
|
|
Loading…
Reference in New Issue