HHH-17133 use ImplicitNamingStrategy for @NaturalId unique keys

This commit is contained in:
Gavin King 2024-03-11 09:25:34 +01:00
parent b75f173318
commit 9c12ea8b11
1 changed files with 55 additions and 5 deletions

View File

@ -46,6 +46,9 @@ import org.hibernate.annotations.common.reflection.XClass;
import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.XProperty;
import org.hibernate.binder.AttributeBinder; import org.hibernate.binder.AttributeBinder;
import org.hibernate.boot.model.IdentifierGeneratorDefinition; import org.hibernate.boot.model.IdentifierGeneratorDefinition;
import org.hibernate.boot.model.naming.Identifier;
import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource;
import org.hibernate.boot.model.relational.Database;
import org.hibernate.boot.spi.AccessType; import org.hibernate.boot.spi.AccessType;
import org.hibernate.boot.spi.InFlightMetadataCollector; import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingContext;
@ -70,6 +73,7 @@ import org.hibernate.usertype.CompositeUserType;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.FetchType.LAZY;
import static java.util.Collections.singletonList;
import static org.hibernate.boot.model.internal.AnyBinder.bindAny; import static org.hibernate.boot.model.internal.AnyBinder.bindAny;
import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId; import static org.hibernate.boot.model.internal.BinderHelper.isCompositeId;
import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal; import static org.hibernate.boot.model.internal.BinderHelper.isGlobalGeneratorNameGlobal;
@ -93,9 +97,9 @@ import static org.hibernate.boot.model.internal.HCANNHelper.findContainingAnnota
import static org.hibernate.boot.model.internal.TimeZoneStorageHelper.resolveTimeZoneStorageCompositeUserType; import static org.hibernate.boot.model.internal.TimeZoneStorageHelper.resolveTimeZoneStorageCompositeUserType;
import static org.hibernate.boot.model.internal.ToOneBinder.bindManyToOne; import static org.hibernate.boot.model.internal.ToOneBinder.bindManyToOne;
import static org.hibernate.boot.model.internal.ToOneBinder.bindOneToOne; import static org.hibernate.boot.model.internal.ToOneBinder.bindOneToOne;
import static org.hibernate.boot.model.naming.Identifier.toIdentifier;
import static org.hibernate.internal.util.StringHelper.qualify; import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.internal.util.collections.CollectionHelper.combine; import static org.hibernate.internal.util.collections.CollectionHelper.combine;
import static org.hibernate.mapping.Constraint.hashedName;
/** /**
* A stateful binder responsible for creating {@link Property} objects. * A stateful binder responsible for creating {@link Property} objects.
@ -811,7 +815,7 @@ public class PropertyBinder {
propertyBinder propertyBinder
); );
addIndexes( inSecondPass, property, columns, joinColumns ); addIndexes( inSecondPass, property, columns, joinColumns );
addNaturalIds( inSecondPass, property, columns, joinColumns ); addNaturalIds( inSecondPass, property, columns, joinColumns, context );
} }
private static AnnotatedColumns bindProperty( private static AnnotatedColumns bindProperty(
@ -1262,21 +1266,67 @@ public class PropertyBinder {
boolean inSecondPass, boolean inSecondPass,
XProperty property, XProperty property,
AnnotatedColumns columns, AnnotatedColumns columns,
AnnotatedJoinColumns joinColumns) { AnnotatedJoinColumns joinColumns,
MetadataBuildingContext context) {
// Natural ID columns must reside in one single UniqueKey within the Table. // Natural ID columns must reside in one single UniqueKey within the Table.
// For now, simply ensure consistent naming. // For now, simply ensure consistent naming.
// TODO: AFAIK, there really isn't a reason for these UKs to be created // TODO: AFAIK, there really isn't a reason for these UKs to be created
// on the SecondPass. This whole area should go away... // on the SecondPass. This whole area should go away...
final NaturalId naturalId = property.getAnnotation( NaturalId.class ); final NaturalId naturalId = property.getAnnotation( NaturalId.class );
if ( naturalId != null ) { if ( naturalId != null ) {
final Database database = context.getMetadataCollector().getDatabase();
if ( joinColumns != null ) { if ( joinColumns != null ) {
final String keyName = "UK_" + hashedName( joinColumns.getTable().getName() + "_NaturalID" ); final Identifier name = context.getBuildingOptions().getImplicitNamingStrategy()
.determineUniqueKeyName(new ImplicitUniqueKeyNameSource() {
@Override
public Identifier getTableName() {
return joinColumns.getTable().getNameIdentifier();
}
@Override
public List<Identifier> getColumnNames() {
return singletonList(toIdentifier("_NaturalID"));
}
@Override
public Identifier getUserProvidedIdentifier() {
return null;
}
@Override
public MetadataBuildingContext getBuildingContext() {
return context;
}
});
final String keyName = name.render( database.getDialect() );
for ( AnnotatedColumn column : joinColumns.getColumns() ) { for ( AnnotatedColumn column : joinColumns.getColumns() ) {
column.addUniqueKey( keyName, inSecondPass ); column.addUniqueKey( keyName, inSecondPass );
} }
} }
else { else {
final String keyName = "UK_" + hashedName( columns.getTable().getName() + "_NaturalID" ); final Identifier name = context.getBuildingOptions().getImplicitNamingStrategy()
.determineUniqueKeyName(new ImplicitUniqueKeyNameSource() {
@Override
public Identifier getTableName() {
return columns.getTable().getNameIdentifier();
}
@Override
public List<Identifier> getColumnNames() {
return singletonList(toIdentifier("_NaturalID"));
}
@Override
public Identifier getUserProvidedIdentifier() {
return null;
}
@Override
public MetadataBuildingContext getBuildingContext() {
return context;
}
});
final String keyName = name.render( database.getDialect() );
for ( AnnotatedColumn column : columns.getColumns() ) { for ( AnnotatedColumn column : columns.getColumns() ) {
column.addUniqueKey( keyName, inSecondPass ); column.addUniqueKey( keyName, inSecondPass );
} }