HHH-8224 unique key, foreign key, and index naming strategies

This commit is contained in:
Brett Meyer 2013-07-31 08:59:43 -04:00 committed by Brett Meyer
parent afc7bdfebe
commit ba59bbf119
17 changed files with 287 additions and 221 deletions

View File

@ -24,9 +24,12 @@
package org.hibernate.cfg; package org.hibernate.cfg;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HashedNameUtil;
/** /**
* The default <tt>NamingStrategy</tt> * The default <tt>NamingStrategy</tt>
@ -93,6 +96,22 @@ public class DefaultNamingStrategy implements NamingStrategy, Serializable {
if (header == null) throw new AssertionFailure("NammingStrategy not properly filled"); if (header == null) throw new AssertionFailure("NammingStrategy not properly filled");
return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility
} }
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames) {
List<String> combinedColumnNames = new ArrayList<String>();
combinedColumnNames.addAll( sourceColumnNames );
combinedColumnNames.addAll( targetColumnNames );
return HashedNameUtil.generateName( "FK_", sourceTableName + "_" + targetTableName, combinedColumnNames );
}
public String uniqueKeyName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "UK_", tableName, columnNames );
}
public String indexName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "IDX_", tableName, columnNames );
}
/** /**
* Return the column name or the unqualified property name * Return the column name or the unqualified property name

View File

@ -23,9 +23,12 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HashedNameUtil;
/** /**
* Naming strategy implementing the EJB3 standards * Naming strategy implementing the EJB3 standards
@ -76,6 +79,22 @@ public class EJB3NamingStrategy implements NamingStrategy, Serializable {
if ( header == null ) throw new AssertionFailure( "NamingStrategy not properly filled" ); if ( header == null ) throw new AssertionFailure( "NamingStrategy not properly filled" );
return columnName( header + "_" + referencedColumnName ); return columnName( header + "_" + referencedColumnName );
} }
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames) {
List<String> combinedColumnNames = new ArrayList<String>();
combinedColumnNames.addAll( sourceColumnNames );
combinedColumnNames.addAll( targetColumnNames );
return HashedNameUtil.generateName( "FK_", sourceTableName + "_" + targetTableName, combinedColumnNames );
}
public String uniqueKeyName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "UK_", tableName, columnNames );
}
public String indexName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "IDX_", tableName, columnNames );
}
public String logicalColumnName(String columnName, String propertyName) { public String logicalColumnName(String columnName, String propertyName) {
return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify( propertyName ); return StringHelper.isNotEmpty( columnName ) ? columnName : StringHelper.unqualify( propertyName );

View File

@ -24,9 +24,12 @@
package org.hibernate.cfg; package org.hibernate.cfg;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.HashedNameUtil;
/** /**
* An improved naming strategy that prefers embedded * An improved naming strategy that prefers embedded
@ -106,6 +109,22 @@ public class ImprovedNamingStrategy implements NamingStrategy, Serializable {
if (header == null) throw new AssertionFailure("NamingStrategy not properly filled"); if (header == null) throw new AssertionFailure("NamingStrategy not properly filled");
return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility return columnName( header ); //+ "_" + referencedColumnName not used for backward compatibility
} }
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames) {
List<String> combinedColumnNames = new ArrayList<String>();
combinedColumnNames.addAll( sourceColumnNames );
combinedColumnNames.addAll( targetColumnNames );
return HashedNameUtil.generateName( "FK_", sourceTableName + "_" + targetTableName, combinedColumnNames );
}
public String uniqueKeyName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "UK_", tableName, columnNames );
}
public String indexName(String tableName, List<String> columnNames) {
return HashedNameUtil.generateName( "IDX_", tableName, columnNames );
}
/** /**
* Return the column name or the unqualified property name * Return the column name or the unqualified property name

View File

@ -23,6 +23,8 @@
*/ */
package org.hibernate.cfg; package org.hibernate.cfg;
import java.util.List;
/** /**
* A set of rules for determining the physical column * A set of rules for determining the physical column
@ -37,6 +39,7 @@ package org.hibernate.cfg;
* @see ImprovedNamingStrategy * @see ImprovedNamingStrategy
* @author Gavin King * @author Gavin King
* @author Emmanuel Bernard * @author Emmanuel Bernard
* @author Brett Meyer
*/ */
public interface NamingStrategy { public interface NamingStrategy {
/** /**
@ -93,6 +96,33 @@ public interface NamingStrategy {
public String foreignKeyColumnName( public String foreignKeyColumnName(
String propertyName, String propertyEntityName, String propertyTableName, String referencedColumnName String propertyName, String propertyEntityName, String propertyTableName, String referencedColumnName
); );
/**
* Return a constraint name for foreign keys that are not explicitly named in the mappings/annotations.
*
* @param tableName The foreign key's source table
* @param columnNames The source columns within the foreign key
* @param tableName The foreign key's target table
* @param columnNames The target columns within the foreign key
* @return The generated foreign key constraint name
*/
public String foreignKeyName(String sourceTableName, List<String> sourceColumnNames,
String targetTableName, List<String> targetColumnNames);
/**
* Return a constraint name for unique keys that are not explicitly named in the mappings/annotations.
*
* @param tableName The unique key's table
* @param columnNames The columns within the unique key
* @return The generated unique key constraint name
*/
public String uniqueKeyName(String tableName, List<String> columnNames);
/**
* Return a constraint name for indexes that are not explicitly named in the mappings/annotations.
*
* @param tableName The index's table
* @param columnNames The columns within the index
* @return The generated index constraint name
*/
public String indexName(String tableName, List<String> columnNames);
/** /**
* Return the logical column name used to refer to a column in the metadata * Return the logical column name used to refer to a column in the metadata
* (like index, unique constraints etc) * (like index, unique constraints etc)

View File

@ -207,4 +207,10 @@ public final class CollectionHelper {
} }
} }
} }
public static <T> List<T> singleEntryList(T entry) {
final List<T> list = new ArrayList<T>();
list.add( entry );
return list;
}
} }

View File

@ -112,11 +112,9 @@ import org.hibernate.metamodel.spi.domain.SingularAttribute;
import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.ForeignKey; import org.hibernate.metamodel.spi.relational.ForeignKey;
import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.Index;
import org.hibernate.metamodel.spi.relational.PrimaryKey; import org.hibernate.metamodel.spi.relational.PrimaryKey;
import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.UniqueKey;
import org.hibernate.metamodel.spi.relational.Value; import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.AggregatedCompositeIdentifierSource; import org.hibernate.metamodel.spi.source.AggregatedCompositeIdentifierSource;
import org.hibernate.metamodel.spi.source.AttributeSource; import org.hibernate.metamodel.spi.source.AttributeSource;
@ -222,7 +220,7 @@ public class Binder implements HelperContext {
this.tableHelper = new TableHelper( this ); this.tableHelper = new TableHelper( this );
this.foreignKeyHelper = new ForeignKeyHelper( this ); this.foreignKeyHelper = new ForeignKeyHelper( this );
this.relationalValueBindingHelper = new RelationalValueBindingHelper( this ); this.relationalValueBindingHelper = new RelationalValueBindingHelper( this );
this.naturalIdUniqueKeyHelper = new NaturalIdUniqueKeyHelper(); this.naturalIdUniqueKeyHelper = new NaturalIdUniqueKeyHelper( this );
this.standardAssociationRelationalBindingResolver = this.standardAssociationRelationalBindingResolver =
new StandardAssociationRelationalBindingResolverImpl( this ); new StandardAssociationRelationalBindingResolverImpl( this );
this.mappedByAssociationRelationalBindingResolver = this.mappedByAssociationRelationalBindingResolver =
@ -1127,49 +1125,28 @@ public class Binder implements HelperContext {
final EntitySource entitySource = bindingContextContext.getEntitySource(); final EntitySource entitySource = bindingContextContext.getEntitySource();
for ( final ConstraintSource constraintSource : entitySource.getConstraints() ) { for ( final ConstraintSource constraintSource : entitySource.getConstraints() ) {
if ( UniqueConstraintSource.class.isInstance( constraintSource ) ) { if ( UniqueConstraintSource.class.isInstance( constraintSource ) ) {
UniqueConstraintSource uniqueConstraintSource = (UniqueConstraintSource) constraintSource; final UniqueConstraintSource uniqueConstraintSource = (UniqueConstraintSource) constraintSource;
UniqueKey uk = new UniqueKey(); final TableSpecification table = findConstraintTable( entityBinding, constraintSource.getTableName() );
TableSpecification table = findConstraintTable( entityBinding, constraintSource.getTableName() ); final List<Column> columns = new ArrayList<Column>();
for ( final String columnName : uniqueConstraintSource.columnNames() ) {
final List<String> columnNames = uniqueConstraintSource.columnNames(); columns.add( tableHelper.locateOrCreateColumn( table, columnName,
final String constraintName = StringHelper.isEmpty( constraintSource.name() ) new ColumnNamingStrategyHelper( null, false ) ) );
? HashedNameUtil.generateName( "UK_", table, columnNames.toArray( new String[columnNames.size()] ) )
: constraintSource.name();
for ( final String columnName : columnNames ) {
uk.addColumn(
tableHelper.locateOrCreateColumn(
table,
columnName,
new ColumnNamingStrategyHelper( null, false )
)
);
} }
uk.setTable( table ); tableHelper.createUniqueKey( table, columns, constraintSource.name() );
uk.setName( constraintName );
table.addUniqueKey( uk );
} }
else if ( IndexConstraintSource.class.isInstance( constraintSource ) ) { else if ( IndexConstraintSource.class.isInstance( constraintSource ) ) {
IndexConstraintSource indexConstraintSource = (IndexConstraintSource) constraintSource; final IndexConstraintSource indexConstraintSource = (IndexConstraintSource) constraintSource;
TableSpecification table = findConstraintTable( entityBinding, constraintSource.getTableName() ); final TableSpecification table = findConstraintTable( entityBinding, constraintSource.getTableName() );
final List<String> columnNames = indexConstraintSource.columnNames(); final List<Column> columns = new ArrayList<Column>();
final List<String> orderings = indexConstraintSource.orderings(); for ( final String columnName : indexConstraintSource.columnNames() ) {
final String constraintName = StringHelper.isEmpty( constraintSource.name() ) columns.add( tableHelper.locateOrCreateColumn( table, columnName,
? HashedNameUtil.generateName( "IDX_", table, columnNames.toArray( new String[columnNames.size()] ) ) new ColumnNamingStrategyHelper( null, false ) ) );
: constraintSource.name();
final Index index = table.getOrCreateIndex( constraintName );
for ( int i = 0; i < columnNames.size(); i++ ) {
Column column = tableHelper.locateOrCreateColumn(
table,
columnNames.get( i ),
new DefaultColumnNamingStrategyHelper( null )
);
index.addColumn( column, orderings.get( i ) );
} }
tableHelper.createIndex( table, columns, constraintSource.name() );
} }
} }
} }
@ -2477,15 +2454,13 @@ public class Binder implements HelperContext {
foreignKey = null; foreignKey = null;
} }
if ( elementSource.isUnique() ) { if ( elementSource.isUnique() ) {
UniqueKey uk = new UniqueKey(); final List<Column> columns = new ArrayList<Column>();
for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) {
if ( ! relationalValueBinding.isDerived() ) { if ( ! relationalValueBinding.isDerived() ) {
uk.addColumn( (Column) relationalValueBinding.getValue() ); columns.add( (Column) relationalValueBinding.getValue() );
} }
} }
uk.setTable( collectionTable ); tableHelper.createUniqueKey( collectionTable, columns, null );
HashedNameUtil.setName("UK_", uk);
collectionTable.addUniqueKey( uk );
} }
elementBinding.setJoinRelationalValueBindings( relationalValueBindings, foreignKey ); elementBinding.setJoinRelationalValueBindings( relationalValueBindings, foreignKey );
typeHelper.bindManyToManyAttributeType( typeHelper.bindManyToManyAttributeType(

View File

@ -0,0 +1,109 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2012, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel.internal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.TableSpecification;
/**
* @author Brett Meyer
*/
public abstract class ConstraintNamingStrategyHelper implements ObjectNameNormalizer.NamingStrategyHelper {
protected final TableSpecification table;
protected final List<Column> columns;
public ConstraintNamingStrategyHelper(TableSpecification table, List<Column> columns) {
this.table = table;
this.columns = columns;
}
@Override
public String determineImplicitName(NamingStrategy strategy) {
return doDetermineImplicitName( strategy, table.getLogicalName().getText(), getColumnNames( columns ) );
}
protected abstract String doDetermineImplicitName(NamingStrategy strategy, String tableName, List<String> columnNames);
@Override
public String handleExplicitName(NamingStrategy strategy, String name) {
return name;
}
public static class UniqueKeyNamingStrategyHelper extends ConstraintNamingStrategyHelper {
public UniqueKeyNamingStrategyHelper(TableSpecification table, List<Column> columns) {
super( table, columns );
}
@Override
protected String doDetermineImplicitName(NamingStrategy strategy, String tableName, List<String> columnNames) {
return strategy.uniqueKeyName( tableName, columnNames );
}
}
public static class ForeignKeyNamingStrategyHelper extends ConstraintNamingStrategyHelper {
// named using a combo of source/target table/columns
private final String targetTableName;
private final List<String> targetColumnNames;
public ForeignKeyNamingStrategyHelper(TableSpecification sourceTable, List<Column> sourceColumns,
TableSpecification targetTable, List<Column> targetColumns) {
super( sourceTable, sourceColumns );
targetTableName = targetTable.getLogicalName().getText();
targetColumnNames = getColumnNames( targetColumns );
}
@Override
protected String doDetermineImplicitName(NamingStrategy strategy, String tableName, List<String> columnNames) {
// combine source and target (if available) to ensure uniqueness
return strategy.foreignKeyName( tableName, columnNames, targetTableName, targetColumnNames );
}
}
public static class IndexNamingStrategyHelper extends ConstraintNamingStrategyHelper {
public IndexNamingStrategyHelper(TableSpecification table, List<Column> columns) {
super( table, columns );
}
@Override
protected String doDetermineImplicitName(NamingStrategy strategy, String tableName, List<String> columnNames) {
return strategy.indexName( tableName, columnNames );
}
}
private static List<String> getColumnNames(List<Column> columns) {
final List<String> columnNames = new ArrayList<String>();
for ( final Column column : columns ) {
columnNames.add( column.getColumnName().getText() );
}
return columnNames;
}
}

View File

@ -27,9 +27,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.annotations.common.util.StringHelper;
import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.cfg.NotYetImplementedException;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.metamodel.internal.ConstraintNamingStrategyHelper.ForeignKeyNamingStrategyHelper;
import org.hibernate.metamodel.spi.binding.AttributeBinding; import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.RelationalValueBinding;
@ -42,7 +42,6 @@ import org.hibernate.metamodel.spi.relational.TableSpecification;
import org.hibernate.metamodel.spi.relational.Value; import org.hibernate.metamodel.spi.relational.Value;
import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource; import org.hibernate.metamodel.spi.source.ForeignKeyContributingSource;
import org.hibernate.metamodel.spi.source.LocalBindingContext; import org.hibernate.metamodel.spi.source.LocalBindingContext;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
/** /**
@ -160,35 +159,11 @@ public class ForeignKeyHelper {
final List<Column> sourceColumns, final List<Column> sourceColumns,
final TableSpecification targetTable, final TableSpecification targetTable,
final List<Column> targetColumns) { final List<Column> targetColumns) {
final String foreignKeyName; final String foreignKeyName = helperContext.relationalIdentifierHelper().normalizeDatabaseIdentifier(
if ( StringHelper.isEmpty( explicitForeignKeyName ) ) { explicitForeignKeyName, new ForeignKeyNamingStrategyHelper(
foreignKeyName = ForeignKey.generateName( sourceTable, targetTable, sourceColumns, targetColumns ); sourceTable, sourceColumns, targetTable, targetColumns ) );
}
else {
foreignKeyName = helperContext.relationalIdentifierHelper().quotedIdentifier( explicitForeignKeyName );
}
ForeignKey foreignKey = locateAndBindForeignKeyByName( foreignKeyName, sourceTable, sourceColumns, targetTable, targetColumns ); ForeignKey foreignKey = locateAndBindForeignKeyByName( foreignKeyName, sourceTable, sourceColumns, targetTable, targetColumns );
if ( foreignKey == null ) {
foreignKey = locateForeignKeyByColumnMapping( sourceTable, sourceColumns, targetTable, targetColumns );
if ( foreignKey != null ) {
if ( foreignKey.getName() == null ) {
// the foreign key name has not be initialized; set it to foreignKeyName
foreignKey.setName( foreignKeyName );
}
else {
// the foreign key name has already been initialized so cannot rename it
// TODO: should this just be INFO?
log.warn(
String.format(
"A foreign key mapped as %s will not be created because foreign key %s already exists with the same column mapping.",
foreignKeyName,
foreignKey.getName()
)
);
}
}
}
if ( foreignKey == null ) { if ( foreignKey == null ) {
// no foreign key found; create one // no foreign key found; create one
foreignKey = sourceTable.createForeignKey( targetTable, foreignKeyName ); foreignKey = sourceTable.createForeignKey( targetTable, foreignKeyName );
@ -197,27 +172,6 @@ public class ForeignKeyHelper {
return foreignKey; return foreignKey;
} }
private static ForeignKey locateForeignKeyByColumnMapping(
final TableSpecification sourceTable,
final List<Column> sourceColumns,
final TableSpecification targetTable,
final List<Column> targetColumns) {
// check for an existing foreign key with the same source/target columns
ForeignKey foreignKey = null;
Iterable<ForeignKey> possibleForeignKeys = sourceTable.locateForeignKey( targetTable );
if ( possibleForeignKeys != null ) {
for ( ForeignKey possibleFK : possibleForeignKeys ) {
if ( possibleFK.getSourceColumns().equals( sourceColumns ) &&
possibleFK.getTargetColumns().equals( targetColumns ) ) {
// this is the foreign key
foreignKey = possibleFK;
break;
}
}
}
return foreignKey;
}
private void bindForeignKeyColumns( private void bindForeignKeyColumns(
final ForeignKey foreignKey, final ForeignKey foreignKey,
final TableSpecification sourceTable, final TableSpecification sourceTable,

View File

@ -27,8 +27,6 @@ import java.util.Arrays;
import java.util.List; import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.metamodel.spi.relational.AbstractConstraint;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.metamodel.spi.relational.TableSpecification;
/** /**
@ -47,11 +45,11 @@ public class HashedNameUtil {
* @param columnNames * @param columnNames
* @return String The generated name * @return String The generated name
*/ */
public static String generateName(String prefix, TableSpecification table, String... columnNames ) { public static String generateName(String prefix, String tableName, String... columnNames ) {
// Use a concatenation that guarantees uniqueness, even if identical names // Use a concatenation that guarantees uniqueness, even if identical names
// exist between all table and column identifiers. // exist between all table and column identifiers.
StringBuilder sb = new StringBuilder( "table`" + table.getLogicalName().getText() + "`" ); StringBuilder sb = new StringBuilder( "table`" + tableName + "`" );
// Ensure a consistent ordering of columns, regardless of the order // Ensure a consistent ordering of columns, regardless of the order
// they were bound. // they were bound.
@ -73,20 +71,12 @@ public class HashedNameUtil {
* @param columns * @param columns
* @return String The generated name * @return String The generated name
*/ */
public static String generateName(String prefix, TableSpecification table, List<Column> columns) { public static String generateName(String prefix, String tableName, List<String> columnNames) {
String[] columnNames = new String[columns.size()]; String[] columnNamesArray = new String[columnNames.size()];
for ( int i = 0; i < columns.size(); i++ ) { for ( int i = 0; i < columnNames.size(); i++ ) {
columnNames[i] = columns.get( i ).getColumnName().getText(); columnNamesArray[i] = columnNames.get( i );
} }
return generateName( prefix, table, columnNames ); return generateName( prefix, tableName, columnNamesArray );
}
/**
* Helper method for {@link #generateName(String, TableSpecification, String...)}.
* Generates and sets a name for an existing constraint.
*/
public static void setName(String prefix, AbstractConstraint constraint) {
constraint.setName( generateName( prefix, constraint.getTable(), constraint.getColumns() ) );
} }
/** /**

View File

@ -31,9 +31,15 @@ import org.hibernate.metamodel.spi.relational.UniqueKey;
* @author Brett Meyer * @author Brett Meyer
*/ */
public class NaturalIdUniqueKeyHelper { public class NaturalIdUniqueKeyHelper {
private final HelperContext helperContext;
private Map<TableSpecification, UniqueKey> naturalIdUniqueKeys private Map<TableSpecification, UniqueKey> naturalIdUniqueKeys
= new HashMap<TableSpecification, UniqueKey>(); = new HashMap<TableSpecification, UniqueKey>();
public NaturalIdUniqueKeyHelper(HelperContext helperContext) {
this.helperContext = helperContext;
}
/** /**
* Natural ID columns must reside in one single UniqueKey within the Table. * Natural ID columns must reside in one single UniqueKey within the Table.
@ -50,6 +56,7 @@ public class NaturalIdUniqueKeyHelper {
uniqueKey = naturalIdUniqueKeys.get( table ); uniqueKey = naturalIdUniqueKeys.get( table );
} }
else { else {
// TODO: For now, leave this out of the naming strategy. It has nothing to do with the columns.
String keyName = "UK_" + HashedNameUtil.hashedName( table.getLogicalName().getText() + "_NaturalID" ); String keyName = "UK_" + HashedNameUtil.hashedName( table.getLogicalName().getText() + "_NaturalID" );
uniqueKey = new UniqueKey(); uniqueKey = new UniqueKey();
uniqueKey.setTable( table ); uniqueKey.setTable( table );

View File

@ -23,13 +23,17 @@
*/ */
package org.hibernate.metamodel.internal; package org.hibernate.metamodel.internal;
import org.jboss.logging.Logger; import java.util.List;
import org.hibernate.TruthValue; import org.hibernate.TruthValue;
import org.hibernate.cfg.ObjectNameNormalizer; import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.internal.ConstraintNamingStrategyHelper.IndexNamingStrategyHelper;
import org.hibernate.metamodel.internal.ConstraintNamingStrategyHelper.UniqueKeyNamingStrategyHelper;
import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.Identifier;
import org.hibernate.metamodel.spi.relational.Index;
import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.TableSpecification; import org.hibernate.metamodel.spi.relational.TableSpecification;
@ -41,6 +45,7 @@ import org.hibernate.metamodel.spi.source.MappingDefaults;
import org.hibernate.metamodel.spi.source.SizeSource; import org.hibernate.metamodel.spi.source.SizeSource;
import org.hibernate.metamodel.spi.source.TableSource; import org.hibernate.metamodel.spi.source.TableSource;
import org.hibernate.metamodel.spi.source.TableSpecificationSource; import org.hibernate.metamodel.spi.source.TableSpecificationSource;
import org.jboss.logging.Logger;
/** /**
* @author Gail Badner * @author Gail Badner
@ -173,14 +178,42 @@ public class TableHelper {
column.setComment( columnSource.getComment() ); column.setComment( columnSource.getComment() );
if (columnSource.isUnique()) { if (columnSource.isUnique()) {
UniqueKey uk = new UniqueKey(); createUniqueKey( table, CollectionHelper.singleEntryList( column ), null );
uk.addColumn( column );
uk.setTable( table );
HashedNameUtil.setName("UK_", uk);
table.addUniqueKey( uk );
} }
return column; return column;
} }
public void createUniqueKey(
final TableSpecification table,
final List<Column> columns,
final String name) {
final UniqueKey uk = new UniqueKey();
for ( final Column column : columns ) {
uk.addColumn( column );
}
uk.setTable( table );
final String normalizedName = normalizeDatabaseIdentifier( name, new UniqueKeyNamingStrategyHelper( table, columns ) );
uk.setName( normalizedName );
table.addUniqueKey( uk );
}
public void createIndex(
final TableSpecification table,
final List<Column> columns,
final String name) {
final Index idx = new Index();
for ( final Column column : columns ) {
idx.addColumn( column );
}
idx.setTable( table );
final String normalizedName = normalizeDatabaseIdentifier( name, new IndexNamingStrategyHelper( table, columns ) );
idx.setName( normalizedName );
table.addIndex( idx );
}
private void resolveColumnNullable( private void resolveColumnNullable(
final TableSpecification table, final TableSpecification table,

View File

@ -25,10 +25,6 @@ package org.hibernate.metamodel.internal.source.annotations.global;
import java.util.Collection; import java.util.Collection;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.logging.Logger;
import org.hibernate.AnnotationException;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.annotations.FetchMode; import org.hibernate.annotations.FetchMode;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
@ -40,12 +36,11 @@ import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotName
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper; import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.MetadataImplementor; import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.SecondaryTable; import org.hibernate.metamodel.spi.binding.SecondaryTable;
import org.hibernate.metamodel.spi.relational.Column;
import org.hibernate.metamodel.spi.relational.Index;
import org.hibernate.metamodel.spi.relational.ObjectName; import org.hibernate.metamodel.spi.relational.ObjectName;
import org.hibernate.metamodel.spi.relational.Schema; import org.hibernate.metamodel.spi.relational.Schema;
import org.hibernate.metamodel.spi.relational.Table; import org.hibernate.metamodel.spi.relational.Table;
import org.hibernate.metamodel.spi.relational.Value; import org.jboss.jandex.AnnotationInstance;
import org.jboss.logging.Logger;
/** /**
* Binds table related information. This binder is called after the entities are bound. * Binds table related information. This binder is called after the entities are bound.
@ -101,13 +96,6 @@ public class TableProcessor {
final AnnotationInstance tableAnnotation, final AnnotationInstance tableAnnotation,
final boolean isSecondaryTable, final boolean isSecondaryTable,
final MetadataImplementor metadata) { final MetadataImplementor metadata) {
for ( AnnotationInstance indexAnnotation : JandexHelper.getValue(
tableAnnotation,
"indexes",
AnnotationInstance[].class
) ) {
bindIndexAnnotation( table, tableAnnotation, indexAnnotation );
}
String comment = JandexHelper.getValue( tableAnnotation, "comment", String.class ); String comment = JandexHelper.getValue( tableAnnotation, "comment", String.class );
if ( StringHelper.isNotEmpty( comment ) ) { if ( StringHelper.isNotEmpty( comment ) ) {
table.addComment( comment.trim() ); table.addComment( comment.trim() );
@ -164,35 +152,4 @@ public class TableProcessor {
} }
private static void bindIndexAnnotation(Table table, AnnotationInstance tableAnnotation, AnnotationInstance indexAnnotation) {
String indexName = JandexHelper.getValue( indexAnnotation, "name", String.class );
String[] columnNames = JandexHelper.getValue( indexAnnotation, "columnNames", String[].class );
if ( columnNames == null ) {
LOG.noColumnsSpecifiedForIndex( indexName, table.toLoggableString() );
return;
}
Index index = table.getOrCreateIndex( indexName );
for ( String columnName : columnNames ) {
Column column = findColumn( table, columnName );
if ( column == null ) {
throw new AnnotationException( "@Index references a unknown column: " + columnName );
}
index.addColumn( column );
}
}
private static Column findColumn(Table table, String columnName) {
Column column = null;
for ( Value value : table.values() ) {
if ( Column.class.isInstance( value ) && Column.class.cast( value )
.getColumnName()
.getText()
.equals( columnName ) ) {
column = (Column) value;
break;
}
}
return column;
}
} }

View File

@ -24,16 +24,13 @@
package org.hibernate.metamodel.spi.relational; package org.hibernate.metamodel.spi.relational;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.metamodel.internal.HashedNameUtil;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
/** /**
@ -260,51 +257,6 @@ public class ForeignKey extends AbstractConstraint {
return columnMappingList; return columnMappingList;
} }
/**
* If a constraint is not explicitly named, this is called to generate
* a unique hash using the source/target table and column names.
* Static so the name can be generated prior to creating the Constraint.
* They're cached, keyed by name, in multiple locations.
*
* @param sourceTable
* @param targetTable
* @param sourceColumns
* @param targetColumns
* @return String The generated name
*/
public static String generateName(TableSpecification sourceTable, TableSpecification targetTable,
List<Column> sourceColumns, List<Column> targetColumns) {
// Use a concatenation that guarantees uniqueness, even if identical names
// exist between all table and column identifiers.
StringBuilder sb = new StringBuilder( "table`" + sourceTable.getLogicalName().getText() + "`" );
sb.append( "table`" + targetTable.getLogicalName().getText() + "`" );
appendColumns( sourceColumns, sb );
appendColumns( targetColumns, sb );
return "FK_" + HashedNameUtil.hashedName( sb.toString() );
}
private static void appendColumns(List<Column> columns, StringBuilder sb) {
// Ensure a consistent ordering of columns, regardless of the order
// they were bound.
// Clone the list, as sometimes a set of order-dependent Column
// bindings are given.
Column[] alphabeticalColumns = columns.toArray( new Column[columns.size()] );
Arrays.sort( alphabeticalColumns, ColumnComparator.INSTANCE );
for ( Column column : alphabeticalColumns ) {
sb.append( "column`" + column.getColumnName().getText() + "`" );
}
}
private static class ColumnComparator implements Comparator<Column> {
public static ColumnComparator INSTANCE = new ColumnComparator();
public int compare(Column col1, Column col2) {
return col1.getColumnName().toString().compareTo( col2.getColumnName().toString() );
}
}
@Override @Override
public String getExportIdentifier() { public String getExportIdentifier() {
return getSourceTable().getLoggableValueQualifier() + ".FK-" + getName(); return getSourceTable().getLoggableValueQualifier() + ".FK-" + getName();

View File

@ -69,7 +69,7 @@ public class InLineView extends AbstractTableSpecification {
} }
@Override @Override
public Index getOrCreateIndex(String name) { public void addIndex(Index index) {
throw new UnsupportedOperationException( "Cannot create index on inline view" ); throw new UnsupportedOperationException( "Cannot create index on inline view" );
} }

View File

@ -33,6 +33,10 @@ import org.hibernate.dialect.Dialect;
*/ */
public class Index extends AbstractConstraint { public class Index extends AbstractConstraint {
public Index() {
this( null, null );
}
protected Index(Table table, String name) { protected Index(Table table, String name) {
super( table, name ); super( table, name );
} }

View File

@ -147,16 +147,8 @@ public class Table extends AbstractTableSpecification implements Exportable {
} }
@Override @Override
public Index getOrCreateIndex(String name) { public void addIndex(Index idx) {
Index result = null; indexes.add( idx );
if ( name != null ) {
result = locateConstraint( indexes, name );
}
if ( result == null ) {
result = new Index( this, name );
indexes.add( result );
}
return result;
} }
@Override @Override

View File

@ -136,7 +136,7 @@ public interface TableSpecification extends ValueContainer, Loggable {
public Iterable<Index> getIndexes(); public Iterable<Index> getIndexes();
public Index getOrCreateIndex(String name); public void addIndex(Index idx);
public Iterable<UniqueKey> getUniqueKeys(); public Iterable<UniqueKey> getUniqueKeys();