diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/ForeignKeyNameSource.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/ForeignKeyNameSource.java new file mode 100644 index 0000000000..9b5090ed54 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/ForeignKeyNameSource.java @@ -0,0 +1,81 @@ +/* + * 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 . + */ +package org.hibernate.boot.internal; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.ImplicitForeignKeyNameSource; +import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.ForeignKey; +import org.hibernate.mapping.Table; + +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; + +public class ForeignKeyNameSource implements ImplicitForeignKeyNameSource { + + final List columnNames; + private final ForeignKey foreignKey; + private final Table table; + private final MetadataBuildingContext buildingContext; + List referencedColumnNames; + + public ForeignKeyNameSource(ForeignKey foreignKey, Table table, MetadataBuildingContext buildingContext) { + this.foreignKey = foreignKey; + this.table = table; + this.buildingContext = buildingContext; + columnNames = extractColumnNames(foreignKey.getColumns()); + referencedColumnNames = null; + } + + @Override + public Identifier getTableName() { + return table.getNameIdentifier(); + } + + @Override + public List getColumnNames() { + return columnNames; + } + + @Override + public Identifier getReferencedTableName() { + return foreignKey.getReferencedTable().getNameIdentifier(); + } + + @Override + public List getReferencedColumnNames() { + if ( referencedColumnNames == null ) { + referencedColumnNames = extractColumnNames( foreignKey.getReferencedColumns() ); + } + return referencedColumnNames; + } + + @Override + public Identifier getUserProvidedIdentifier() { + return foreignKey.getName() != null ? Identifier.toIdentifier(foreignKey.getName()) : null; + } + + @Override + public MetadataBuildingContext getBuildingContext() { + return buildingContext; + } + + private List extractColumnNames(List columns) { + if ( columns == null || columns.isEmpty() ) { + return emptyList(); + } + + final List columnNames = arrayList( columns.size() ); + for ( Column column : columns ) { + columnNames.add( column.getNameIdentifier( buildingContext ) ); + } + return columnNames; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index f78494c23d..377067630d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -53,7 +53,6 @@ import org.hibernate.boot.model.internal.SecondaryTableFromAnnotationSecondPass; import org.hibernate.boot.model.internal.SecondaryTableSecondPass; import org.hibernate.boot.model.internal.SetBasicValueTypeSecondPass; import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.boot.model.naming.ImplicitForeignKeyNameSource; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.ExportableProducer; @@ -111,9 +110,6 @@ import jakarta.persistence.Embeddable; import jakarta.persistence.Entity; import jakarta.persistence.MapsId; -import static java.util.Collections.emptyList; -import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; - /** * The implementation of the {@linkplain InFlightMetadataCollector in-flight * metadata collector contract}. @@ -1935,26 +1931,16 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, protected void secondPassCompileForeignKeys(Table table, Set done, MetadataBuildingContext buildingContext) throws MappingException { - table.createForeignKeys(); + table.createForeignKeys( buildingContext ); final Dialect dialect = getDatabase().getJdbcEnvironment().getDialect(); for ( ForeignKey foreignKey : table.getForeignKeys().values() ) { if ( !done.contains( foreignKey ) ) { done.add( foreignKey ); - final String referencedEntityName = foreignKey.getReferencedEntityName(); - if ( referencedEntityName == null ) { - throw new MappingException( "An association from the table '" + foreignKey.getTable().getName() + - "' does not specify the referenced entity" ); - } + final PersistentClass referencedClass = foreignKey.resolveReferencedClass(this); - log.debugf( "Resolving reference to class: %s", referencedEntityName ); - final PersistentClass referencedClass = getEntityBinding( referencedEntityName ); - if ( referencedClass == null ) { - throw new MappingException( "An association from the table '" + foreignKey.getTable().getName() + - "' refers to an unmapped class '" + referencedEntityName + "'" ); - } if ( referencedClass.isJoinedSubclass() ) { - secondPassCompileForeignKeys( referencedClass.getSuperclass().getTable(), done, buildingContext ); + secondPassCompileForeignKeys( referencedClass.getSuperclass().getTable(), done, buildingContext); } // the ForeignKeys created in the first pass did not have their referenced table initialized @@ -1971,19 +1957,6 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, } } - private List extractColumnNames(List columns) { - if ( columns == null || columns.isEmpty() ) { - return emptyList(); - } - - final List columnNames = arrayList( columns.size() ); - for ( Column column : columns ) { - columnNames.add( getDatabase().toIdentifier( column.getQuotedName() ) ); - } - return columnNames; - - } - private void processPropertyReferences() { if ( delayedPropertyReferenceHandlers == null ) { return; @@ -2173,53 +2146,4 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector, log.debugf( "Ignoring exception thrown when trying to build IdentifierGenerator as part of Metadata building", e ); } } - - private class ForeignKeyNameSource implements ImplicitForeignKeyNameSource { - final List columnNames; - private final ForeignKey foreignKey; - private final Table table; - private final MetadataBuildingContext buildingContext; - List referencedColumnNames; - - public ForeignKeyNameSource(ForeignKey foreignKey, Table table, MetadataBuildingContext buildingContext) { - this.foreignKey = foreignKey; - this.table = table; - this.buildingContext = buildingContext; - columnNames = extractColumnNames(foreignKey.getColumns()); - referencedColumnNames = null; - } - - @Override - public Identifier getTableName() { - return table.getNameIdentifier(); - } - - @Override - public List getColumnNames() { - return columnNames; - } - - @Override - public Identifier getReferencedTableName() { - return foreignKey.getReferencedTable().getNameIdentifier(); - } - - @Override - public List getReferencedColumnNames() { - if ( referencedColumnNames == null ) { - referencedColumnNames = extractColumnNames( foreignKey.getReferencedColumns() ); - } - return referencedColumnNames; - } - - @Override - public Identifier getUserProvidedIdentifier() { - return foreignKey.getName() != null ? Identifier.toIdentifier( foreignKey.getName() ) : null; - } - - @Override - public MetadataBuildingContext getBuildingContext() { - return buildingContext; - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java index fe40a9902c..8ebc322c63 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedColumn.java @@ -301,7 +301,9 @@ public class AnnotatedColumn { mappingColumn.setArrayLength( arrayLength ); mappingColumn.setNullable( nullable ); mappingColumn.setSqlType( sqlType ); - mappingColumn.setUnique( unique ); + if ( unique ) { + getParent().getTable().createUniqueKey( mappingColumn, getBuildingContext() ); + } for ( CheckConstraint constraint : checkConstraints ) { mappingColumn.addCheckConstraint( constraint ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java index 73913ccbe7..8b689e9161 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumn.java @@ -213,7 +213,7 @@ public class AnnotatedJoinColumn extends AnnotatedColumn { AnnotatedJoinColumns parent, MetadataBuildingContext context) { final String defaultColumnName = context.getMetadataCollector() - .getLogicalColumnName( identifier.getTable(), identifier.getColumns().get(0).getQuotedName() ); + .getLogicalColumnName( identifier.getTable(), identifier.getColumns().get(0).getQuotedName() ); return primaryKeyJoinColumn != null || joinColumn != null ? buildExplicitInheritanceJoinColumn( primaryKeyJoinColumn, joinColumn, parent, context, defaultColumnName ) : buildImplicitInheritanceJoinColumn( parent, context, defaultColumnName ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java index bbba35ccdd..95b1cd485a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotatedJoinColumns.java @@ -610,7 +610,8 @@ public class AnnotatedJoinColumns extends AnnotatedColumns { ) ); } - return database.toIdentifier( ( (Column) selectable ).getQuotedName() ); + final Column column = (Column) selectable; + return column.getNameIdentifier( getBuildingContext() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java index dbc0c34c5a..ae4908b018 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/BinderHelper.java @@ -350,7 +350,7 @@ public class BinderHelper { else { ownerEntity.addProperty( result ); } - embeddedComponent.createUniqueKey(); //make it unique + embeddedComponent.createUniqueKey( context ); //make it unique return result; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java index c51987cacc..e6e3ad81ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexBinder.java @@ -8,10 +8,7 @@ package org.hibernate.boot.model.internal; import jakarta.persistence.UniqueConstraint; import org.hibernate.AnnotationException; -import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.boot.model.naming.ImplicitIndexNameSource; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; -import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -28,9 +25,7 @@ import java.util.List; import java.util.Locale; import java.util.StringTokenizer; -import static java.util.Collections.emptyList; import static org.hibernate.internal.util.StringHelper.isEmpty; -import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; /** * Responsible for interpreting {@link jakarta.persistence.Index} and @@ -233,57 +228,4 @@ class IndexBinder { } } } - - private class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource { - private final MetadataBuildingContext buildingContext; - private final Table table; - private final String[] columnNames; - private final String originalKeyName; - - public IndexOrUniqueKeyNameSource(MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) { - this.buildingContext = buildingContext; - this.table = table; - this.columnNames = columnNames; - this.originalKeyName = originalKeyName; - } - - @Override - public MetadataBuildingContext getBuildingContext() { - return buildingContext; - } - - @Override - public Identifier getTableName() { - return table.getNameIdentifier(); - } - - private List columnNameIdentifiers; - - @Override - public List getColumnNames() { - // be lazy about building these - if ( columnNameIdentifiers == null ) { - columnNameIdentifiers = toIdentifiers( columnNames ); - } - return columnNameIdentifiers; - } - - @Override - public Identifier getUserProvidedIdentifier() { - return originalKeyName != null ? Identifier.toIdentifier( originalKeyName ) : null; - } - } - - private List toIdentifiers(String[] names) { - if ( names == null ) { - return emptyList(); - } - - final List columnNames = arrayList( names.length ); - for ( String name : names ) { - columnNames.add( getDatabase().toIdentifier( name ) ); - } - return columnNames; - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexOrUniqueKeyNameSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexOrUniqueKeyNameSource.java new file mode 100644 index 0000000000..51924ae8b5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/IndexOrUniqueKeyNameSource.java @@ -0,0 +1,72 @@ +/* + * 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 . + */ +package org.hibernate.boot.model.internal; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.ImplicitIndexNameSource; +import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource; +import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.mapping.Table; + +import java.util.List; + +import static java.util.Collections.emptyList; +import static org.hibernate.boot.model.naming.Identifier.toIdentifier; +import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; + +class IndexOrUniqueKeyNameSource implements ImplicitIndexNameSource, ImplicitUniqueKeyNameSource { + private final MetadataBuildingContext buildingContext; + private final Table table; + private final String[] columnNames; + private final String originalKeyName; + + public IndexOrUniqueKeyNameSource( + MetadataBuildingContext buildingContext, Table table, String[] columnNames, String originalKeyName) { + this.buildingContext = buildingContext; + this.table = table; + this.columnNames = columnNames; + this.originalKeyName = originalKeyName; + } + + @Override + public MetadataBuildingContext getBuildingContext() { + return buildingContext; + } + + @Override + public Identifier getTableName() { + return table.getNameIdentifier(); + } + + private List columnNameIdentifiers; + + @Override + public List getColumnNames() { + // be lazy about building these + if ( columnNameIdentifiers == null ) { + columnNameIdentifiers = toIdentifiers( columnNames ); + } + return columnNameIdentifiers; + } + + @Override + public Identifier getUserProvidedIdentifier() { + return originalKeyName != null ? toIdentifier( originalKeyName ) : null; + } + + private List toIdentifiers(String[] names) { + if ( names == null ) { + return emptyList(); + } + + final List columnNames = arrayList( names.length ); + for ( String name : names ) { + columnNames.add( buildingContext.getMetadataCollector().getDatabase().toIdentifier( name ) ); + } + return columnNames; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java index 26438774c9..f27bf485cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/TableBinder.java @@ -568,7 +568,7 @@ public class TableBinder { } value.createForeignKey( referencedEntity, joinColumns ); if ( unique ) { - value.createUniqueKey(); + value.createUniqueKey( buildingContext ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java index 12790823bd..e62f53dbd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/ImplicitNamingStrategyJpaCompliantImpl.java @@ -11,7 +11,10 @@ import java.io.Serializable; import org.hibernate.HibernateException; import org.hibernate.boot.model.source.spi.AttributePath; import org.hibernate.boot.spi.MetadataBuildingContext; -import org.hibernate.internal.util.StringHelper; + +import static org.hibernate.boot.model.naming.ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION; +import static org.hibernate.internal.util.StringHelper.isNotEmpty; +import static org.hibernate.internal.util.StringHelper.unqualify; /** * Implementation of the {@link ImplicitNamingStrategy} contract, generally @@ -47,12 +50,12 @@ public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStr protected String transformEntityName(EntityNaming entityNaming) { // prefer the JPA entity name, if specified... - if ( StringHelper.isNotEmpty( entityNaming.getJpaEntityName() ) ) { + if ( isNotEmpty( entityNaming.getJpaEntityName() ) ) { return entityNaming.getJpaEntityName(); } else { // otherwise, use the Hibernate entity name - return StringHelper.unqualify( entityNaming.getEntityName() ); + return unqualify( entityNaming.getEntityName() ); } } @@ -67,7 +70,6 @@ public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStr final String name = source.getOwningPhysicalTableName() + '_' + source.getNonOwningPhysicalTableName(); - return toIdentifier( name, source.getBuildingContext() ); } @@ -80,12 +82,9 @@ public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStr // aka: // if owning entity has a JPA entity name: {OWNER JPA ENTITY NAME}_{COLLECTION ATTRIBUTE NAME} // otherwise: {OWNER ENTITY NAME}_{COLLECTION ATTRIBUTE NAME} - final String entityName = transformEntityName( source.getOwningEntityNaming() ); - - final String name = entityName + final String name = transformEntityName( source.getOwningEntityNaming() ) + '_' + transformAttributePath( source.getOwningAttributePath() ); - return toIdentifier( name, source.getBuildingContext() ); } @@ -141,16 +140,15 @@ public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStr final String name; - if ( source.getNature() == ImplicitJoinColumnNameSource.Nature.ELEMENT_COLLECTION + String referencedColumnName = source.getReferencedColumnName().getText(); + if ( source.getNature() == ELEMENT_COLLECTION || source.getAttributePath() == null ) { name = transformEntityName( source.getEntityNaming() ) - + '_' - + source.getReferencedColumnName().getText(); + + '_' + referencedColumnName; } else { name = transformAttributePath( source.getAttributePath() ) - + '_' - + source.getReferencedColumnName().getText(); + + '_' + referencedColumnName; } return toIdentifier( name, source.getBuildingContext() ); @@ -165,17 +163,21 @@ public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStr @Override public Identifier determineAnyDiscriminatorColumnName(ImplicitAnyDiscriminatorColumnNameSource source) { + final MetadataBuildingContext buildingContext = source.getBuildingContext(); return toIdentifier( - transformAttributePath( source.getAttributePath() ) + "_" + source.getBuildingContext().getMappingDefaults().getImplicitDiscriminatorColumnName(), - source.getBuildingContext() + transformAttributePath( source.getAttributePath() ) + + "_" + buildingContext.getMappingDefaults().getImplicitDiscriminatorColumnName(), + buildingContext ); } @Override public Identifier determineAnyKeyColumnName(ImplicitAnyKeyColumnNameSource source) { + final MetadataBuildingContext buildingContext = source.getBuildingContext(); return toIdentifier( - transformAttributePath( source.getAttributePath() ) + "_" + source.getBuildingContext().getMappingDefaults().getImplicitIdColumnName(), - source.getBuildingContext() + transformAttributePath( source.getAttributePath() ) + + "_" + buildingContext.getMappingDefaults().getImplicitIdColumnName(), + buildingContext ); } @@ -198,41 +200,35 @@ public class ImplicitNamingStrategyJpaCompliantImpl implements ImplicitNamingStr @Override public Identifier determineForeignKeyName(ImplicitForeignKeyNameSource source) { - Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); + final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); + final MetadataBuildingContext buildingContext = source.getBuildingContext(); return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( - NamingHelper.withCharset( source.getBuildingContext().getBuildingOptions().getSchemaCharset() ).generateHashedFkName( - "FK", - source.getTableName(), - source.getReferencedTableName(), - source.getColumnNames() - ), - source.getBuildingContext() + NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() ) + .generateHashedFkName( "FK", source.getTableName(), + source.getReferencedTableName(), source.getColumnNames() ), + buildingContext ); } @Override public Identifier determineUniqueKeyName(ImplicitUniqueKeyNameSource source) { - Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); + final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); + final MetadataBuildingContext buildingContext = source.getBuildingContext(); return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( - NamingHelper.withCharset( source.getBuildingContext().getBuildingOptions().getSchemaCharset() ).generateHashedConstraintName( - "UK", - source.getTableName(), - source.getColumnNames() - ), - source.getBuildingContext() + NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() ) + .generateHashedConstraintName( "UK", source.getTableName(), source.getColumnNames() ), + buildingContext ); } @Override public Identifier determineIndexName(ImplicitIndexNameSource source) { - Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); + final Identifier userProvidedIdentifier = source.getUserProvidedIdentifier(); + final MetadataBuildingContext buildingContext = source.getBuildingContext(); return userProvidedIdentifier != null ? userProvidedIdentifier : toIdentifier( - NamingHelper.withCharset( source.getBuildingContext().getBuildingOptions().getSchemaCharset() ).generateHashedConstraintName( - "IDX", - source.getTableName(), - source.getColumnNames() - ), - source.getBuildingContext() + NamingHelper.withCharset( buildingContext.getBuildingOptions().getSchemaCharset() ) + .generateHashedConstraintName( "IDX", source.getTableName(), source.getColumnNames() ), + buildingContext ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/NamingHelper.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/NamingHelper.java index 3d7ed81f6d..69a194b077 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/NamingHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/NamingHelper.java @@ -16,6 +16,8 @@ import java.util.List; import org.hibernate.HibernateException; +import static java.util.Comparator.comparing; + /** * @author Steve Ebersole */ @@ -48,19 +50,13 @@ public class NamingHelper { Identifier tableName, Identifier referencedTableName, List columnNames) { - final Identifier[] columnNamesArray; - if ( columnNames == null || columnNames.isEmpty() ) { - columnNamesArray = new Identifier[0]; - } - else { - columnNamesArray = columnNames.toArray( new Identifier[ columnNames.size() ] ); - } - return generateHashedFkName( prefix, tableName, referencedTableName, - columnNamesArray + columnNames == null || columnNames.isEmpty() + ? new Identifier[0] + : columnNames.toArray( new Identifier[0] ) ); } @@ -118,15 +114,7 @@ public class NamingHelper { // Clone the list, as sometimes a set of order-dependent Column // bindings are given. Identifier[] alphabeticalColumns = columnNames.clone(); - Arrays.sort( - alphabeticalColumns, - new Comparator() { - @Override - public int compare(Identifier o1, Identifier o2) { - return o1.getCanonicalName().compareTo( o2.getCanonicalName() ); - } - } - ); + Arrays.sort( alphabeticalColumns, comparing(Identifier::getCanonicalName) ); for ( Identifier columnName : alphabeticalColumns ) { sb.append( "column`" ).append( columnName ).append( "`" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index c52f3323bf..d18eeb4169 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -160,9 +160,12 @@ import org.hibernate.usertype.CompositeUserType; import org.hibernate.usertype.ParameterizedType; import org.hibernate.usertype.UserType; +import static org.hibernate.boot.model.naming.Identifier.toIdentifier; +import static org.hibernate.boot.model.source.internal.hbm.Helper.reflectedPropertyClass; import static org.hibernate.cfg.AvailableSettings.USE_ENTITY_WHERE_CLAUSE_FOR_COLLECTIONS; import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; import static org.hibernate.internal.util.StringHelper.getNonEmptyOrConjunctionIfBothNonEmpty; +import static org.hibernate.internal.util.StringHelper.isNotEmpty; import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty; import static org.hibernate.mapping.SimpleValue.DEFAULT_ID_GEN_STRATEGY; @@ -406,7 +409,7 @@ public class ModelBinder { ); // NOTE : entitySource#isLazy already accounts for MappingDefaults#areEntitiesImplicitlyLazy - if ( StringHelper.isNotEmpty( entitySource.getProxy() ) ) { + if ( isNotEmpty( entitySource.getProxy() ) ) { final String qualifiedProxyName = sourceDocument.qualifyClassName( entitySource.getProxy() ); entityDescriptor.setProxyInterfaceName( qualifiedProxyName ); entityDescriptor.setLazy( true ); @@ -439,7 +442,7 @@ public class ModelBinder { entityDescriptor.setBatchSize( entitySource.getBatchSize() ); entityDescriptor.setSelectBeforeUpdate( entitySource.isSelectBeforeUpdate() ); - if ( StringHelper.isNotEmpty( entitySource.getCustomPersisterClassName() ) ) { + if ( isNotEmpty( entitySource.getCustomPersisterClassName() ) ) { try { entityDescriptor.setEntityPersisterClass( sourceDocument.getBootstrapContext() @@ -623,8 +626,8 @@ public class ModelBinder { int count = 0; @Override public Identifier determineImplicitName(LocalMetadataBuildingContext context) { - final Column column = primaryTable.getPrimaryKey().getColumn( count++ ); - return database.toIdentifier( column.getQuotedName() ); + return primaryTable.getPrimaryKey().getColumn( count++ ) + .getNameIdentifier( metadataBuildingContext ); } } ); @@ -799,7 +802,7 @@ public class ModelBinder { identifierValue.getTable().setIdentifierValue( identifierValue ); - if ( StringHelper.isNotEmpty( unsavedValue ) ) { + if ( isNotEmpty( unsavedValue ) ) { identifierValue.setNullValue( unsavedValue ); } else if ( DEFAULT_ID_GEN_STRATEGY.equals( identifierValue.getIdentifierGeneratorStrategy() ) ) { @@ -1696,7 +1699,7 @@ public class ModelBinder { inLineViewSource.getSelectStatement(), false ); - logicalTableName = Identifier.toIdentifier( inLineViewSource.getLogicalName() ); + logicalTableName = toIdentifier( inLineViewSource.getLogicalName() ); } secondaryTableJoin.setTable( secondaryTable ); @@ -1738,8 +1741,8 @@ public class ModelBinder { int count = 0; @Override public Identifier determineImplicitName(LocalMetadataBuildingContext context) { - final Column correspondingColumn = entityTableXref.getPrimaryTable().getPrimaryKey().getColumn( count++ ); - return database.toIdentifier( correspondingColumn.getQuotedName() ); + return entityTableXref.getPrimaryTable().getPrimaryKey().getColumn( count++ ) + .getNameIdentifier( metadataBuildingContext ); } } ); @@ -2062,7 +2065,7 @@ public class ModelBinder { oneToOneBinding.setUnwrapProxy( oneToOneSource.getFetchCharacteristics().isUnwrapProxies() ); - if ( StringHelper.isNotEmpty( oneToOneSource.getReferencedEntityAttributeName() ) ) { + if ( isNotEmpty( oneToOneSource.getReferencedEntityAttributeName() ) ) { oneToOneBinding.setReferencedPropertyName( oneToOneSource.getReferencedEntityAttributeName() ); oneToOneBinding.setReferenceToPrimaryKey( false ); } @@ -2077,7 +2080,7 @@ public class ModelBinder { DEPRECATION_LOGGER.logDeprecationOfEmbedXmlSupport(); } - if ( StringHelper.isNotEmpty( oneToOneSource.getExplicitForeignKeyName() ) ) { + if ( isNotEmpty( oneToOneSource.getExplicitForeignKeyName() ) ) { oneToOneBinding.setForeignKeyName( oneToOneSource.getExplicitForeignKeyName() ); } @@ -2096,7 +2099,7 @@ public class ModelBinder { referencedEntityName = manyToOneSource.getReferencedEntityName(); } else { - Class reflectedPropertyClass = Helper.reflectedPropertyClass( sourceDocument, containingClassName, attributeName ); + Class reflectedPropertyClass = reflectedPropertyClass( sourceDocument, containingClassName, attributeName ); if ( reflectedPropertyClass != null ) { referencedEntityName = reflectedPropertyClass.getName(); } @@ -2137,7 +2140,7 @@ public class ModelBinder { prop ); - if ( StringHelper.isNotEmpty( manyToOneSource.getCascadeStyleName() ) ) { + if ( isNotEmpty( manyToOneSource.getCascadeStyleName() ) ) { // todo : would be better to delay this the end of binding (second pass, etc) // in order to properly allow for a singular unique column for a many-to-one to // also trigger a "logical one-to-one". As-is, this can occasionally lead to @@ -2174,7 +2177,7 @@ public class ModelBinder { // NOTE : no type information to bind manyToOneBinding.setReferencedEntityName( referencedEntityName ); - if ( StringHelper.isNotEmpty( manyToOneSource.getReferencedEntityAttributeName() ) ) { + if ( isNotEmpty( manyToOneSource.getReferencedEntityAttributeName() ) ) { manyToOneBinding.setReferencedPropertyName( manyToOneSource.getReferencedEntityAttributeName() ); manyToOneBinding.setReferenceToPrimaryKey( false ); } @@ -2196,7 +2199,7 @@ public class ModelBinder { manyToOneBinding.setIgnoreNotFound( manyToOneSource.isIgnoreNotFound() ); - if ( StringHelper.isNotEmpty( manyToOneSource.getExplicitForeignKeyName() ) ) { + if ( isNotEmpty( manyToOneSource.getExplicitForeignKeyName() ) ) { manyToOneBinding.setForeignKeyName( manyToOneSource.getExplicitForeignKeyName() ); } @@ -2465,7 +2468,7 @@ public class ModelBinder { property.setName( propertySource.getName() ); property.setPropertyAccessorName( - StringHelper.isNotEmpty( propertySource.getPropertyAccessorName() ) + isNotEmpty( propertySource.getPropertyAccessorName() ) ? propertySource.getPropertyAccessorName() : mappingDocument.getMappingDefaults().getImplicitPropertyAccessorName() ); @@ -2474,7 +2477,7 @@ public class ModelBinder { final CascadeStyleSource cascadeStyleSource = (CascadeStyleSource) propertySource; property.setCascade( - StringHelper.isNotEmpty( cascadeStyleSource.getCascadeStyleName() ) + isNotEmpty( cascadeStyleSource.getCascadeStyleName() ) ? cascadeStyleSource.getCascadeStyleName() : mappingDocument.getMappingDefaults().getImplicitCascadeStyleName() ); @@ -2613,7 +2616,7 @@ public class ModelBinder { } else { log.debugf( "Binding component [%s]", role ); - if ( StringHelper.isNotEmpty( explicitComponentClassName ) ) { + if ( isNotEmpty( explicitComponentClassName ) ) { try { final Class componentClass = sourceDocument.getBootstrapContext() .getClassLoaderAccess() @@ -2643,12 +2646,8 @@ public class ModelBinder { else if ( componentBinding.getOwner().hasPojoRepresentation() ) { log.tracef( "Attempting to determine component class by reflection %s", role ); final Class reflectedComponentClass; - if ( StringHelper.isNotEmpty( containingClassName ) && StringHelper.isNotEmpty( propertyName ) ) { - reflectedComponentClass = Helper.reflectedPropertyClass( - sourceDocument, - containingClassName, - propertyName - ); + if ( isNotEmpty( containingClassName ) && isNotEmpty( propertyName ) ) { + reflectedComponentClass = reflectedPropertyClass( sourceDocument, containingClassName, propertyName ); } else { reflectedComponentClass = null; @@ -2671,11 +2670,7 @@ public class ModelBinder { } // todo : anything else to pass along? - bindAllCompositeAttributes( - sourceDocument, - embeddableSource, - componentBinding - ); + bindAllCompositeAttributes( sourceDocument, embeddableSource, componentBinding ); if ( embeddableSource.getParentReferenceAttributeName() != null ) { componentBinding.setParentProperty( embeddableSource.getParentReferenceAttributeName() ); @@ -2689,7 +2684,7 @@ public class ModelBinder { } } // todo : we may need to delay this - componentBinding.getOwner().getTable().createUniqueKey( cols ); + componentBinding.getOwner().getTable().createUniqueKey( cols, metadataBuildingContext ); } } @@ -2847,7 +2842,7 @@ public class ModelBinder { if ( isTable ) { final TableSource tableSource = (TableSource) tableSpecSource; - if ( StringHelper.isNotEmpty( tableSource.getExplicitTableName() ) ) { + if ( isNotEmpty( tableSource.getExplicitTableName() ) ) { logicalTableName = database.toIdentifier( tableSource.getExplicitTableName() ); } else { @@ -2939,7 +2934,7 @@ public class ModelBinder { if ( isTable ) { final TableSource tableSource = (TableSource) tableSpecSource; table.setRowId( tableSource.getRowId() ); - if ( StringHelper.isNotEmpty( tableSource.getCheckConstraint() ) ) { + if ( isNotEmpty( tableSource.getCheckConstraint() ) ) { table.addCheckConstraint( tableSource.getCheckConstraint() ); } } @@ -2952,7 +2947,7 @@ public class ModelBinder { } private Identifier determineCatalogName(TableSpecificationSource tableSpecSource) { - if ( StringHelper.isNotEmpty( tableSpecSource.getExplicitCatalogName() ) ) { + if ( isNotEmpty( tableSpecSource.getExplicitCatalogName() ) ) { return database.toIdentifier( tableSpecSource.getExplicitCatalogName() ); } else { @@ -2961,7 +2956,7 @@ public class ModelBinder { } private Identifier determineSchemaName(TableSpecificationSource tableSpecSource) { - if ( StringHelper.isNotEmpty( tableSpecSource.getExplicitSchemaName() ) ) { + if ( isNotEmpty( tableSpecSource.getExplicitSchemaName() ) ) { return database.toIdentifier( tableSpecSource.getExplicitSchemaName() ); } else { @@ -3183,8 +3178,8 @@ public class ModelBinder { final TableSource tableSource = (TableSource) tableSpecSource; Identifier logicalName; - if ( StringHelper.isNotEmpty( tableSource.getExplicitTableName() ) ) { - logicalName = Identifier.toIdentifier( + if ( isNotEmpty( tableSource.getExplicitTableName() ) ) { + logicalName = toIdentifier( tableSource.getExplicitTableName(), mappingDocument.getMappingDefaults().shouldImplicitlyQuoteIdentifiers() ); @@ -3486,7 +3481,7 @@ public class ModelBinder { elementBinding.setForeignKeyName( elementSource.getExplicitForeignKeyName() ); elementBinding.setReferencedEntityName( elementSource.getReferencedEntityName() ); - if ( StringHelper.isNotEmpty( elementSource.getReferencedEntityAttributeName() ) ) { + if ( isNotEmpty( elementSource.getReferencedEntityAttributeName() ) ) { elementBinding.setReferencedPropertyName( elementSource.getReferencedEntityAttributeName() ); elementBinding.setReferenceToPrimaryKey( false ); } @@ -4180,37 +4175,37 @@ public class ModelBinder { if ( selectable instanceof Column ) { final Column column = (Column) selectable; uk.addColumn( column ); - columnNames.add( - mappingDocument.getMetadataCollector().getDatabase().toIdentifier( column.getQuotedName() ) - ); + columnNames.add( column.getNameIdentifier( mappingDocument ) ); } } uk.addColumns( attributeBinding.getValue() ); } - final Identifier ukName = mappingDocument.getBuildingOptions().getImplicitNamingStrategy().determineUniqueKeyName( - new ImplicitUniqueKeyNameSource() { - @Override - public Identifier getTableName() { - return entityBinding.getTable().getNameIdentifier(); - } + final Identifier ukName = mappingDocument.getBuildingOptions().getImplicitNamingStrategy() + .determineUniqueKeyName( + new ImplicitUniqueKeyNameSource() { + @Override + public Identifier getTableName() { + return entityBinding.getTable().getNameIdentifier(); + } - @Override - public List getColumnNames() { - return columnNames; - } + @Override + public List getColumnNames() { + return columnNames; + } - @Override - public MetadataBuildingContext getBuildingContext() { - return mappingDocument; - } + @Override + public MetadataBuildingContext getBuildingContext() { + return mappingDocument; + } - @Override - public Identifier getUserProvidedIdentifier() { - return uk.getName() != null ? Identifier.toIdentifier( uk.getName() ) : null; - } - } - ); + @Override + public Identifier getUserProvidedIdentifier() { + final String name = uk.getName(); + return name == null ? null : toIdentifier( name ); + } + } + ); uk.setName( ukName.render( mappingDocument.getMetadataCollector().getDatabase().getDialect() ) ); entityBinding.getTable().addUniqueKey( uk ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/RelationalObjectBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/RelationalObjectBinder.java index 8a0345e72d..362906eb42 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/RelationalObjectBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/RelationalObjectBinder.java @@ -155,6 +155,9 @@ public class RelationalObjectBinder { column.setNullable( interpretNullability( columnSource.isNullable(), areColumnsNullableByDefault ) ); column.setUnique( columnSource.isUnique() ); + if ( columnSource.isUnique() && table != null ) { + table.createUniqueKey( column, simpleValue.getBuildingContext() ); + } String checkCondition = columnSource.getCheckCondition(); if ( checkCondition != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/ExportableColumn.java b/hibernate-core/src/main/java/org/hibernate/id/ExportableColumn.java index 554c11b553..851281666c 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/ExportableColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/id/ExportableColumn.java @@ -139,7 +139,7 @@ public class ExportableColumn extends Column { } @Override - public void createUniqueKey() { + public void createUniqueKey(MetadataBuildingContext context) { } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/AggregateColumn.java b/hibernate-core/src/main/java/org/hibernate/mapping/AggregateColumn.java index 52c39f361c..7c94c49bc6 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/AggregateColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/AggregateColumn.java @@ -29,6 +29,7 @@ public class AggregateColumn extends Column { setName( column.getQuotedName() ); setNullable( column.isNullable() ); setUnique( column.isUnique() ); + setUniqueKeyName( column.getUniqueKeyName() ); setSqlType( column.getSqlType() ); setSqlTypeCode( column.getSqlTypeCode() ); uniqueInteger = column.uniqueInteger; //usually useless diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java index 7bda2a0768..6a473913e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Collection.java @@ -499,7 +499,7 @@ public abstract class Collection implements Fetchable, Value, Filterable, SoftDe } @Override - public void createUniqueKey() { + public void createUniqueKey(MetadataBuildingContext context) { } public boolean isSimpleValue() { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java index faffed48b2..c49a71461e 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java @@ -13,17 +13,19 @@ import java.util.Locale; import java.util.Objects; import org.hibernate.AssertionFailure; +import org.hibernate.Internal; import org.hibernate.MappingException; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.TruthValue; +import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.spi.Mapping; import org.hibernate.loader.internal.AliasConstantsHelper; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.query.sqm.function.SqmFunctionRegistry; -import org.hibernate.query.sqm.internal.TypecheckUtil; import org.hibernate.sql.Template; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.type.BasicType; @@ -61,6 +63,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn private String name; private boolean nullable = true; private boolean unique; + private String uniqueKeyName; private String sqlTypeName; private Integer sqlTypeCode; private Boolean sqlTypeLob; @@ -126,6 +129,12 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn } } + @Internal + public Identifier getNameIdentifier(MetadataBuildingContext buildingContext) { + return buildingContext.getMetadataCollector().getDatabase() + .toIdentifier( getQuotedName() ); + } + public boolean isExplicit() { return explicit; } @@ -566,6 +575,14 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn this.unique = unique; } + public String getUniqueKeyName() { + return uniqueKeyName; + } + + public void setUniqueKeyName(String keyName) { + uniqueKeyName = keyName; + } + public boolean isQuoted() { return quoted; } @@ -778,6 +795,7 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn copy.quoted = quoted; copy.nullable = nullable; copy.unique = unique; + copy.uniqueKeyName = uniqueKeyName; copy.sqlTypeName = sqlTypeName; copy.sqlTypeCode = sqlTypeCode; copy.uniqueInteger = uniqueInteger; //usually useless @@ -792,5 +810,4 @@ public class Column implements Selectable, Serializable, Cloneable, ColumnTypeIn copy.columnSize = columnSize; return copy; } - } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java b/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java index 4858c50736..1a94131556 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java @@ -47,7 +47,10 @@ public abstract class Constraint implements Exportable, Serializable { * They're cached, keyed by name, in multiple locations. * * @return String The generated name + * + * @deprecated This method does not respect the {@link org.hibernate.boot.model.naming.ImplicitNamingStrategy} */ + @Deprecated(since = "6.5", forRemoval = true) public static String generateName(String prefix, Table table, Column... columns) { // Use a concatenation that guarantees uniqueness, even if identical names // exist between all table and column identifiers. @@ -69,7 +72,10 @@ public abstract class Constraint implements Exportable, Serializable { * Helper method for {@link #generateName(String, Table, Column...)}. * * @return String The generated name + * + * @deprecated This method does not respect the {@link org.hibernate.boot.model.naming.ImplicitNamingStrategy} */ + @Deprecated(since = "6.5", forRemoval = true) public static String generateName(String prefix, Table table, List columns) { // N.B. legacy APIs are involved: can't trust that the columns List is actually // containing Column instances - the generic type isn't consistently enforced. @@ -89,7 +95,10 @@ public abstract class Constraint implements Exportable, Serializable { * * @param name The name to be hashed. * @return String The hashed name. + * + * @deprecated Only used from deprecated methods */ + @Deprecated(since = "6.5", forRemoval = true) public static String hashedName(String name) { try { final MessageDigest md = MessageDigest.getInstance( "MD5" ); @@ -147,6 +156,10 @@ public abstract class Constraint implements Exportable, Serializable { this.table = table; } + /** + * @deprecated No longer used + */ + @Deprecated(forRemoval = true) public boolean isGenerated(Dialect dialect) { return true; } @@ -172,6 +185,8 @@ public abstract class Constraint implements Exportable, Serializable { /** * @return String The prefix to use in generated constraint names. Examples: * "UK_", "FK_", and "PK_". + * @deprecated No longer used, should be removed */ + @Deprecated(since="6.5", forRemoval = true) public abstract String generatedConstraintNamePrefix(); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/DenormalizedTable.java b/hibernate-core/src/main/java/org/hibernate/mapping/DenormalizedTable.java index f2a5489950..0eb210f38a 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/DenormalizedTable.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/DenormalizedTable.java @@ -12,8 +12,10 @@ import java.util.Iterator; import java.util.List; import org.hibernate.Internal; +import org.hibernate.boot.internal.ForeignKeyNameSource; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.internal.util.collections.JoinedList; /** @@ -59,15 +61,20 @@ public class DenormalizedTable extends Table { } @Override - public void createForeignKeys() { - includedTable.createForeignKeys(); + public void createForeignKeys(MetadataBuildingContext context) { + includedTable.createForeignKeys( context ); for ( ForeignKey foreignKey : includedTable.getForeignKeys().values() ) { + final PersistentClass referencedClass = + foreignKey.resolveReferencedClass( context.getMetadataCollector() ); + // the ForeignKeys created in the first pass did not have their referenced table initialized + if ( foreignKey.getReferencedTable() == null ) { + foreignKey.setReferencedTable( referencedClass.getTable() ); + } createForeignKey( - Constraint.generateName( - foreignKey.generatedConstraintNamePrefix(), - this, - foreignKey.getColumns() - ), + context.getBuildingOptions() + .getImplicitNamingStrategy() + .determineForeignKeyName( new ForeignKeyNameSource( foreignKey, this, context ) ) + .render( context.getMetadataCollector().getDatabase().getDialect() ), foreignKey.getColumns(), foreignKey.getReferencedEntityName(), foreignKey.getKeyDefinition(), @@ -105,7 +112,7 @@ public class DenormalizedTable extends Table { return includedTable.getPrimaryKey(); } - @Override @Deprecated + @Override @Deprecated(forRemoval = true) public Iterator getUniqueKeyIterator() { if ( !includedTable.isPhysicalTable() ) { for ( UniqueKey uniqueKey : includedTable.getUniqueKeys().values() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java index 519ce803cf..34ce44eeb6 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java @@ -10,8 +10,10 @@ import java.util.ArrayList; import java.util.Iterator; import java.util.List; +import org.hibernate.Internal; import org.hibernate.MappingException; import org.hibernate.annotations.OnDeleteAction; +import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; @@ -232,7 +234,25 @@ public class ForeignKey extends Constraint { } + @Deprecated(forRemoval = true) public String generatedConstraintNamePrefix() { return "FK_"; } + + @Internal + public PersistentClass resolveReferencedClass(Metadata metadata) { + final String referencedEntityName = getReferencedEntityName(); + if ( referencedEntityName == null ) { + throw new MappingException( "An association from the table '" + getTable().getName() + + "' does not specify the referenced entity" ); + } + + final PersistentClass referencedClass = metadata.getEntityBinding( referencedEntityName ); + if ( referencedClass == null ) { + throw new MappingException( "An association from the table '" + getTable().getName() + + "' refers to an unmapped class '" + referencedEntityName + "'" ); + } + + return referencedClass; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java b/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java index 6e527d4b4d..e56392b3e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ManyToOne.java @@ -60,9 +60,9 @@ public class ManyToOne extends ToOne { } @Override - public void createUniqueKey() { + public void createUniqueKey(MetadataBuildingContext context) { if ( !hasFormula() ) { - getTable().createUniqueKey( getConstraintColumns() ); + getTable().createUniqueKey( getConstraintColumns(), context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/OneToMany.java b/hibernate-core/src/main/java/org/hibernate/mapping/OneToMany.java index 37a4a68a0d..2a4e8fad1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/OneToMany.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/OneToMany.java @@ -6,7 +6,6 @@ */ package org.hibernate.mapping; -import java.util.Iterator; import java.util.List; import java.util.Objects; @@ -91,7 +90,7 @@ public class OneToMany implements Value { } @Override - public void createUniqueKey() { + public void createUniqueKey(MetadataBuildingContext context) { } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java b/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java index 4c1e54563c..56fd2100f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/OneToOne.java @@ -94,9 +94,9 @@ public class OneToOne extends ToOne { } @Override - public void createUniqueKey() { + public void createUniqueKey(MetadataBuildingContext context) { if ( !hasFormula() && getColumnSpan()>0 ) { - getTable().createUniqueKey( getConstraintColumns() ); + getTable().createUniqueKey( getConstraintColumns(), context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java index 2da567eaaa..dd2105e439 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java @@ -100,7 +100,8 @@ public class PrimaryKey extends Constraint { } return buf.append(')').toString(); } - + + @Deprecated(forRemoval = true) public String generatedConstraintNamePrefix() { return "PK_"; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index 81aa371835..ea4153af94 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -368,11 +368,11 @@ public abstract class SimpleValue implements KeyValue { } @Override - public void createUniqueKey() { + public void createUniqueKey(MetadataBuildingContext context) { if ( hasFormula() ) { throw new MappingException( "unique key constraint involves formulas" ); } - getTable().createUniqueKey( getConstraintColumns() ); + getTable().createUniqueKey( getConstraintColumns(), context ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java index 83ccd8ba4e..49ef37dd39 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java @@ -23,12 +23,14 @@ import org.hibernate.MappingException; import org.hibernate.Remove; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource; import org.hibernate.boot.model.relational.ContributableDatabaseObject; import org.hibernate.boot.model.relational.InitCommand; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.InFlightMetadataCollector; +import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.extract.spi.TableInformation; @@ -36,9 +38,11 @@ import org.hibernate.tool.schema.internal.StandardTableMigrator; import org.jboss.logging.Logger; import static java.util.Collections.emptyList; +import static java.util.Collections.singletonList; import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableMap; import static java.util.stream.Collectors.toList; +import static org.hibernate.boot.model.naming.Identifier.toIdentifier; /** * A mapping model object representing a relational database {@linkplain jakarta.persistence.Table table}. @@ -151,7 +155,7 @@ public class Table implements Serializable, ContributableDatabaseObject { } public void setName(String name) { - this.name = Identifier.toIdentifier( name ); + this.name = toIdentifier( name ); } public String getName() { @@ -193,7 +197,7 @@ public class Table implements Serializable, ContributableDatabaseObject { } public void setSchema(String schema) { - this.schema = Identifier.toIdentifier( schema ); + this.schema = toIdentifier( schema ); } public String getSchema() { @@ -213,7 +217,7 @@ public class Table implements Serializable, ContributableDatabaseObject { } public void setCatalog(String catalog) { - this.catalog = Identifier.toIdentifier( catalog ); + this.catalog = toIdentifier( catalog ); } public String getCatalog() { @@ -321,7 +325,10 @@ public class Table implements Serializable, ContributableDatabaseObject { return unmodifiableMap( indexes ); } - @Deprecated(since = "6.0") + /** + * @deprecated No longer used, should be removed + */ + @Deprecated(since = "6.0", forRemoval = true) public Iterator getForeignKeyIterator() { return getForeignKeys().values().iterator(); } @@ -330,7 +337,10 @@ public class Table implements Serializable, ContributableDatabaseObject { return unmodifiableMap( foreignKeys ); } - @Deprecated(since = "6.0") + /** + * @deprecated No longer used, should be removed + */ + @Deprecated(since = "6.0", forRemoval = true) public Iterator getUniqueKeyIterator() { return getUniqueKeys().values().iterator(); } @@ -508,10 +518,84 @@ public class Table implements Serializable, ContributableDatabaseObject { return uniqueKey; } + /** + * Mark the given column unique. + */ + public void createUniqueKey(Column column, MetadataBuildingContext context) { + final String keyName = context.getBuildingOptions().getImplicitNamingStrategy() + .determineUniqueKeyName( new ImplicitUniqueKeyNameSource() { + @Override + public Identifier getTableName() { + return name; + } + + @Override + public List getColumnNames() { + return singletonList( column.getNameIdentifier( context ) ); + } + + @Override + public Identifier getUserProvidedIdentifier() { + return null; + } + + @Override + public MetadataBuildingContext getBuildingContext() { + return context; + } + } ) + .render( context.getMetadataCollector().getDatabase().getDialect() ); + column.setUniqueKeyName( keyName ); + column.setUnique( true ); + } + /** * If there is one given column, mark it unique, otherwise * create a {@link UniqueKey} comprising the given columns. */ + public void createUniqueKey(List keyColumns, MetadataBuildingContext context) { + if ( keyColumns.size() == 1 ) { + createUniqueKey( keyColumns.get(0), context ); + } + else { + final String keyName = context.getBuildingOptions().getImplicitNamingStrategy() + .determineUniqueKeyName( new ImplicitUniqueKeyNameSource() { + @Override + public Identifier getTableName() { + return name; + } + + @Override + public List getColumnNames() { + return keyColumns.stream() + .map( column -> column.getNameIdentifier( context ) ) + .collect(toList()); + } + + @Override + public Identifier getUserProvidedIdentifier() { + return null; + } + + @Override + public MetadataBuildingContext getBuildingContext() { + return context; + } + } ) + .render( context.getMetadataCollector().getDatabase().getDialect() ); + final UniqueKey uniqueKey = getOrCreateUniqueKey( keyName ); + for ( Column keyColumn : keyColumns ) { + uniqueKey.addColumn( keyColumn ); + } + } + } + + /** + * If there is one given column, mark it unique, otherwise + * create a {@link UniqueKey} comprising the given columns. + * @deprecated Use {@link #createUniqueKey(List, MetadataBuildingContext)} + */ + @Deprecated(since = "6.5", forRemoval = true) public void createUniqueKey(List keyColumns) { if ( keyColumns.size() == 1 ) { keyColumns.get(0).setUnique( true ); @@ -540,7 +624,7 @@ public class Table implements Serializable, ContributableDatabaseObject { return uniqueKey; } - public void createForeignKeys() { + public void createForeignKeys(MetadataBuildingContext context) { } public ForeignKey createForeignKey(String keyName, List keyColumns, String referencedEntityName, String keyDefinition) { @@ -699,12 +783,18 @@ public class Table implements Serializable, ContributableDatabaseObject { this.comment = comment; } - @Deprecated(since = "6.0") + /** + * @deprecated No longer used, should be removed + */ + @Deprecated(since = "6.0", forRemoval = true) public Iterator getCheckConstraintsIterator() { return getCheckConstraints().iterator(); } - @Deprecated(since = "6.2") + /** + * @deprecated No longer used, should be removed + */ + @Deprecated(since = "6.2", forRemoval = true) public List getCheckConstraints() { return checkConstraints.stream().map( CheckConstraint::getConstraint ).collect( toList() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java index 282ce1c1e9..b5660e3122 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java @@ -47,6 +47,7 @@ public class UniqueKey extends Constraint { return columnOrderMap; } + @Deprecated(forRemoval = true) public String generatedConstraintNamePrefix() { return "UK_"; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Value.java b/hibernate-core/src/main/java/org/hibernate/mapping/Value.java index c75d629da0..e5f2f9c09d 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Value.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Value.java @@ -7,7 +7,6 @@ package org.hibernate.mapping; import java.io.Serializable; -import java.util.Iterator; import java.util.List; import java.util.Set; @@ -142,7 +141,7 @@ public interface Value extends Serializable { // called when this is the foreign key of a // @OneToOne with a FK, or a @OneToMany with // a join table - void createUniqueKey(); + void createUniqueKey(MetadataBuildingContext context); boolean isSimpleValue(); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java index 832b85b248..8e6a630e4b 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java @@ -9,7 +9,6 @@ package org.hibernate.tool.schema.internal; import java.util.Locale; import org.hibernate.boot.Metadata; -import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.Sequence; import org.hibernate.boot.model.relational.SqlStringGenerationContext; @@ -33,6 +32,8 @@ import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.jboss.logging.Logger; +import static org.hibernate.boot.model.naming.Identifier.toIdentifier; + /** * Base implementation of {@link SchemaValidator}. * @@ -139,7 +140,9 @@ public abstract class AbstractSchemaValidator implements SchemaValidator { } for ( Column column : table.getColumns() ) { - final ColumnInformation existingColumn = tableInformation.getColumn( Identifier.toIdentifier( column.getQuotedName() ) ); + final ColumnInformation existingColumn = + //QUESTION: should this use metadata.getDatabase().toIdentifier( column.getQuotedName() ) + tableInformation.getColumn( toIdentifier( column.getQuotedName() ) ); if ( existingColumn == null ) { throw new SchemaManagementException( String.format( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java index 746ea24d60..72acae9854 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/ColumnDefinitions.java @@ -114,7 +114,12 @@ class ColumnDefinitions { Dialect dialect, SqlStringGenerationContext context) { if ( column.isUnique() && !table.isPrimaryKey( column ) ) { - final String keyName = Constraint.generateName( "UK_", table, column); + String uniqueKeyName = column.getUniqueKeyName(); + final String keyName = uniqueKeyName == null + // fallback in case the ImplicitNamingStrategy name was not assigned + // (we don't have access to the ImplicitNamingStrategy here) + ? Constraint.generateName( "UK_", table, column ) + : uniqueKeyName; final UniqueKey uniqueKey = table.getOrCreateUniqueKey( keyName ); uniqueKey.addColumn( column ); definition.append( dialect.getUniqueDelegate().getColumnDefinitionUniquenessFragment( column, context ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java index 057cd47711..00cce3e07c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java @@ -144,7 +144,7 @@ public class UniqueConstraintDropTest { if ( getDialect().supportsIfExistsBeforeConstraintName() ) { regex += " if exists"; } - regex += " uk_.*"; + regex += " uk.*"; if ( getDialect().supportsIfExistsAfterConstraintName() ) { regex += " if exists"; }