light refactoring

This commit is contained in:
Gavin 2022-11-25 19:34:03 +01:00 committed by Gavin King
parent 3ba90c004c
commit 13f4c8c285
3 changed files with 242 additions and 186 deletions

View File

@ -1931,45 +1931,8 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
Identifier nameIdentifier; Identifier nameIdentifier;
ImplicitForeignKeyNameSource foreignKeyNameSource = new ImplicitForeignKeyNameSource() { nameIdentifier = getMetadataBuildingOptions().getImplicitNamingStrategy()
final List<Identifier> columnNames = extractColumnNames( foreignKey.getColumns() ); .determineForeignKeyName( new ForeignKeyNameSource( foreignKey, table, buildingContext ) );
List<Identifier> referencedColumnNames = null;
@Override
public Identifier getTableName() {
return table.getNameIdentifier();
}
@Override
public List<Identifier> getColumnNames() {
return columnNames;
}
@Override
public Identifier getReferencedTableName() {
return foreignKey.getReferencedTable().getNameIdentifier();
}
@Override
public List<Identifier> 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;
}
};
nameIdentifier = getMetadataBuildingOptions().getImplicitNamingStrategy().determineForeignKeyName(foreignKeyNameSource);
foreignKey.setName( nameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() ) ); foreignKey.setName( nameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() ) );
@ -2063,93 +2026,53 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
//column equals and hashcode is based on column name //column equals and hashcode is based on column name
} }
catch ( MappingException e ) { catch ( MappingException e ) {
// If at least 1 columnName does exist, 'columns' will contain a mix of Columns and nulls. In order // If at least 1 columnName does exist, 'columns' will contain a mix of Columns and nulls.
// to exhaustively report all of the unbound columns at once, w/o an NPE in // In order to exhaustively report all the unbound columns at once, w/o an NPE in
// Constraint#generateName's array sorting, simply create a fake Column. // Constraint#generateName's array sorting, simply create a fake Column.
columns[index] = new Column( logicalColumnName ); columns[index] = new Column( logicalColumnName );
unboundNoLogical.add( columns[index] ); unboundNoLogical.add( columns[index] );
} }
} }
final String originalKeyName = keyName; createIndexOrUniqueKey( table, keyName, nameExplicit, columnNames, orderings, unique, buildingContext, columns, unbound );
if ( unique ) { if ( unbound.size() > 0 || unboundNoLogical.size() > 0 ) {
final Identifier keyNameIdentifier = getMetadataBuildingOptions().getImplicitNamingStrategy().determineUniqueKeyName( throwUnableToCreateConstraint( table, columnNames, unique, unbound, unboundNoLogical );
new ImplicitUniqueKeyNameSource() { }
@Override
public MetadataBuildingContext getBuildingContext() {
return buildingContext;
} }
@Override private void createIndexOrUniqueKey(
public Identifier getTableName() { Table table,
return table.getNameIdentifier(); String originalKeyName,
} boolean nameExplicit,
String[] columnNames,
private List<Identifier> columnNameIdentifiers; String[] orderings,
boolean unique,
@Override MetadataBuildingContext buildingContext,
public List<Identifier> getColumnNames() { Column[] columns,
// be lazy about building these Set<Column> unbound) {
if ( columnNameIdentifiers == null ) { if (unique) {
columnNameIdentifiers = toIdentifiers( columnNames ); createUniqueKey( table, originalKeyName, nameExplicit, columnNames, orderings, buildingContext, columns, unbound );
}
return columnNameIdentifiers;
}
@Override
public Identifier getUserProvidedIdentifier() {
return originalKeyName != null ? Identifier.toIdentifier( originalKeyName ) : null;
}
}
);
keyName = keyNameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() );
UniqueKey uk = table.getOrCreateUniqueKey( keyName );
uk.setNameExplicit( nameExplicit );
for ( int i = 0; i < columns.length; i++ ) {
Column column = columns[i];
String order = orderings != null ? orderings[i] : null;
if ( table.containsColumn( column ) ) {
uk.addColumn( column, order );
unbound.remove( column );
}
}
} }
else { else {
final Identifier keyNameIdentifier = getMetadataBuildingOptions().getImplicitNamingStrategy().determineIndexName( createIndex( table, originalKeyName, columnNames, orderings, buildingContext, columns, unbound );
new ImplicitIndexNameSource() { }
@Override
public MetadataBuildingContext getBuildingContext() {
return buildingContext;
} }
@Override private void createIndex(
public Identifier getTableName() { Table table,
return table.getNameIdentifier(); String originalKeyName,
} String[] columnNames,
String[] orderings,
MetadataBuildingContext buildingContext,
Column[] columns,
Set<Column> unbound) {
final Identifier keyNameIdentifier = getMetadataBuildingOptions().getImplicitNamingStrategy()
.determineIndexName( new IndexOrUniqueKeyNameSource( buildingContext, table, columnNames, originalKeyName ) );
final String keyName = keyNameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() );
private List<Identifier> columnNameIdentifiers; final Index index = table.getOrCreateIndex( keyName );
for (int i = 0; i < columns.length; i++ ) {
@Override
public List<Identifier> 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;
}
}
);
keyName = keyNameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() );
Index index = table.getOrCreateIndex( keyName );
for ( int i = 0; i < columns.length; i++ ) {
Column column = columns[i]; Column column = columns[i];
String order = orderings != null ? orderings[i] : null; String order = orderings != null ? orderings[i] : null;
if ( table.containsColumn( column ) ) { if ( table.containsColumn( column ) ) {
@ -2159,29 +2082,58 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
} }
} }
if ( unbound.size() > 0 || unboundNoLogical.size() > 0 ) { private void createUniqueKey(
StringBuilder sb = new StringBuilder( "Unable to create " ); Table table,
if ( unique ) { String originalKeyName,
sb.append( "unique key constraint (" ); boolean nameExplicit,
String[] columnNames,
String[] orderings,
MetadataBuildingContext buildingContext,
Column[] columns,
Set<Column> unbound) {
final Identifier keyNameIdentifier = getMetadataBuildingOptions().getImplicitNamingStrategy()
.determineUniqueKeyName( new IndexOrUniqueKeyNameSource( buildingContext, table, columnNames, originalKeyName ) );
final String keyName = keyNameIdentifier.render( getDatabase().getJdbcEnvironment().getDialect() );
final UniqueKey uk = table.getOrCreateUniqueKey( keyName );
uk.setNameExplicit(nameExplicit);
for (int i = 0; i < columns.length; i++ ) {
Column column = columns[i];
String order = orderings != null ? orderings[i] : null;
if ( table.containsColumn( column ) ) {
uk.addColumn( column, order );
unbound.remove( column );
}
}
}
private static void throwUnableToCreateConstraint(
Table table,
String[] columnNames,
boolean unique,
Set<Column> unbound,
Set<Column> unboundNoLogical) {
final StringBuilder message = new StringBuilder( "Unable to create " );
if (unique) {
message.append( "unique key constraint (" );
} }
else { else {
sb.append( "index (" ); message.append( "index (" );
} }
for ( String columnName : columnNames ) { for ( String columnName : columnNames) {
sb.append( columnName ).append( ", " ); message.append( columnName ).append( ", " );
} }
sb.setLength( sb.length() - 2 ); message.setLength( message.length() - 2 );
sb.append( ") on table '" ).append( table.getName() ).append( "' since the column " ); message.append( ") on table '" ).append( table.getName() ).append( "' since the column " );
for ( Column column : unbound ) { for ( Column column : unbound) {
sb.append("'").append( column.getName() ).append( "', " ); message.append("'").append( column.getName() ).append( "', " );
} }
for ( Column column : unboundNoLogical ) { for ( Column column : unboundNoLogical) {
sb.append("'").append( column.getName() ).append( "', " ); message.append("'").append( column.getName() ).append( "', " );
}
sb.setLength( sb.length() - 2 );
sb.append( " was not found (specify the correct column name, which depends on the naming strategy, and may not be the same as the entity property name)" );
throw new AnnotationException( sb.toString() );
} }
message.setLength( message.length() - 2 );
message.append( " was not found (specify the correct column name, which depends on the naming strategy, and may not be the same as the entity property name)" );
throw new AnnotationException( message.toString() );
} }
private void processJPAIndexHolders(MetadataBuildingContext buildingContext) { private void processJPAIndexHolders(MetadataBuildingContext buildingContext) {
@ -2379,4 +2331,93 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
} }
return identifier.render( dialect ); return identifier.render( dialect );
} }
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<Identifier> columnNameIdentifiers;
@Override
public List<Identifier> 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 class ForeignKeyNameSource implements ImplicitForeignKeyNameSource {
final List<Identifier> columnNames;
private final ForeignKey foreignKey;
private final Table table;
private final MetadataBuildingContext buildingContext;
List<Identifier> 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<Identifier> getColumnNames() {
return columnNames;
}
@Override
public Identifier getReferencedTableName() {
return foreignKey.getReferencedTable().getNameIdentifier();
}
@Override
public List<Identifier> 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;
}
}
} }

View File

@ -2638,24 +2638,18 @@ public abstract class CollectionBinder {
SimpleValue value, SimpleValue value,
boolean unique) { boolean unique) {
if ( hasMappedBy() ) { if ( hasMappedBy() ) {
final Property property = targetEntity.getRecursiveProperty( mappedBy ); bindUnownedManyToManyInverseForeignKey( targetEntity, joinColumns, value );
final List<Selectable> mappedByColumns = mappedByColumns( targetEntity, property );
final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
for ( Selectable selectable: mappedByColumns ) {
firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value );
}
final String referencedPropertyName = buildingContext.getMetadataCollector()
.getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy );
if ( referencedPropertyName != null ) {
//TODO always a many to one?
( (ManyToOne) value ).setReferencedPropertyName( referencedPropertyName );
buildingContext.getMetadataCollector()
.addUniquePropertyReference( targetEntity.getEntityName(), referencedPropertyName );
}
( (ManyToOne) value ).setReferenceToPrimaryKey( referencedPropertyName == null );
value.createForeignKey();
} }
else { else {
bindOwnedManyToManyForeignKeyMappedBy( targetEntity, joinColumns, value, unique );
}
}
private void bindOwnedManyToManyForeignKeyMappedBy(
PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns,
SimpleValue value,
boolean unique) { // true when it's actually a logical @OneToMany
createSyntheticPropertyReference( createSyntheticPropertyReference(
joinColumns, joinColumns,
targetEntity, targetEntity,
@ -2677,6 +2671,27 @@ public abstract class CollectionBinder {
buildingContext buildingContext
); );
} }
private void bindUnownedManyToManyInverseForeignKey(
PersistentClass targetEntity,
AnnotatedJoinColumns joinColumns,
SimpleValue value) {
final Property property = targetEntity.getRecursiveProperty( mappedBy );
final List<Selectable> mappedByColumns = mappedByColumns(targetEntity, property );
final AnnotatedJoinColumn firstColumn = joinColumns.getJoinColumns().get(0);
for ( Selectable selectable: mappedByColumns ) {
firstColumn.linkValueUsingAColumnCopy( (Column) selectable, value);
}
final String referencedPropertyName = buildingContext.getMetadataCollector()
.getPropertyReferencedAssociation( targetEntity.getEntityName(), mappedBy );
if ( referencedPropertyName != null ) {
//TODO always a many to one?
( (ManyToOne) value).setReferencedPropertyName( referencedPropertyName );
buildingContext.getMetadataCollector()
.addUniquePropertyReference( targetEntity.getEntityName(), referencedPropertyName );
}
( (ManyToOne) value).setReferenceToPrimaryKey( referencedPropertyName == null );
value.createForeignKey();
} }
private static List<Selectable> mappedByColumns(PersistentClass referencedEntity, Property property) { private static List<Selectable> mappedByColumns(PersistentClass referencedEntity, Property property) {

View File

@ -20,7 +20,7 @@ import org.hibernate.internal.util.StringHelper;
*/ */
public class UniqueKey extends Constraint { public class UniqueKey extends Constraint {
private final Map<Column, String> columnOrderMap = new HashMap<>(); private final Map<Column, String> columnOrderMap = new HashMap<>();
private boolean nameExplicit; private boolean nameExplicit; // true when the constraint name was explicitly specified by @UniqueConstraint annotation
@Override @Deprecated(since="6.2") @Override @Deprecated(since="6.2")
public String sqlConstraintString( public String sqlConstraintString(