fix issue with circularity detection

This commit is contained in:
Andrea Boriero 2020-02-20 10:38:13 +00:00
parent 1df4824d5f
commit 90cd4e5c8f
6 changed files with 40 additions and 60 deletions

View File

@ -13,10 +13,4 @@ import org.hibernate.sql.results.graph.Fetchable;
*/ */
public interface Association extends Fetchable { public interface Association extends Fetchable {
ForeignKeyDescriptor getForeignKeyDescriptor(); ForeignKeyDescriptor getForeignKeyDescriptor();
/**
* The column expressions that identify this association.
* Mainly used in circularity detection
*/
String[] getIdentifyingColumnExpressions();
} }

View File

@ -47,7 +47,6 @@ public class EntityCollectionPart
private final EntityMappingType entityMappingType; private final EntityMappingType entityMappingType;
private ModelPart fkTargetModelPart; private ModelPart fkTargetModelPart;
private String[] identifyingColumns;
@SuppressWarnings("WeakerAccess") @SuppressWarnings("WeakerAccess")
public EntityCollectionPart( public EntityCollectionPart(
@ -75,14 +74,6 @@ public class EntityCollectionPart
else { else {
fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null ); fkTargetModelPart = entityMappingType.findSubPart( fkTargetModelPartName, null );
} }
final List<String> identifyingColumnsList = new ArrayList<>();
collectionDescriptor.getAttributeMapping().getKeyDescriptor().visitReferringColumns(
(containingTableExpression, columnExpression, jdbcMapping) -> {
identifyingColumnsList.add( containingTableExpression + "." + columnExpression );
}
);
this.identifyingColumns = identifyingColumnsList.toArray( new String[0] );
} }
@ -212,9 +203,4 @@ public class EntityCollectionPart
// todo (6.0) : this will not strictly work - we'd want a new ForeignKeyDescriptor that points the other direction // todo (6.0) : this will not strictly work - we'd want a new ForeignKeyDescriptor that points the other direction
return collectionDescriptor.getAttributeMapping().getKeyDescriptor(); return collectionDescriptor.getAttributeMapping().getKeyDescriptor();
} }
@Override
public String[] getIdentifyingColumnExpressions() {
return identifyingColumns;
}
} }

View File

@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Objects;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -57,6 +58,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
private final String targetColumnExpression; private final String targetColumnExpression;
private final JdbcMapping jdbcMapping; private final JdbcMapping jdbcMapping;
private final ForeignKeyDirection fKeyDirection; private final ForeignKeyDirection fKeyDirection;
private final int hasCode;
public SimpleForeignKeyDescriptor( public SimpleForeignKeyDescriptor(
ForeignKeyDirection fKeyDirection, ForeignKeyDirection fKeyDirection,
@ -71,6 +73,13 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
this.targetColumnContainingTable = targetColumnContainingTable; this.targetColumnContainingTable = targetColumnContainingTable;
this.targetColumnExpression = targetColumnExpression; this.targetColumnExpression = targetColumnExpression;
this.jdbcMapping = jdbcMapping; this.jdbcMapping = jdbcMapping;
this.hasCode = Objects.hash(
keyColumnContainingTable,
keyColumnExpression,
targetColumnContainingTable,
targetColumnExpression
);
} }
@Override @Override
@ -405,4 +414,24 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
public String getTargetColumnExpression() { public String getTargetColumnExpression() {
return targetColumnExpression; return targetColumnExpression;
} }
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
SimpleForeignKeyDescriptor that = (SimpleForeignKeyDescriptor) o;
return Objects.equals( keyColumnContainingTable, that.keyColumnContainingTable ) &&
Objects.equals( targetColumnContainingTable, that.targetColumnContainingTable ) &&
Objects.equals( keyColumnExpression, that.keyColumnExpression ) &&
Objects.equals( targetColumnExpression, that.targetColumnExpression );
}
@Override
public int hashCode() {
return this.hasCode;
}
} }

View File

@ -6,10 +6,6 @@
*/ */
package org.hibernate.metamodel.mapping.internal; package org.hibernate.metamodel.mapping.internal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
@ -81,11 +77,6 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
private ForeignKeyDescriptor foreignKeyDescriptor; private ForeignKeyDescriptor foreignKeyDescriptor;
private String identifyingColumnsTableExpression; private String identifyingColumnsTableExpression;
private String inverseIdentifyingColumnsTableExpression;
private String[] identifyingColumns;
public SingularAssociationAttributeMapping( public SingularAssociationAttributeMapping(
String name, String name,
@ -139,30 +130,14 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
this.foreignKeyDescriptor = foreignKeyDescriptor; this.foreignKeyDescriptor = foreignKeyDescriptor;
final String identifyingColumnsTableExpression; final String identifyingColumnsTableExpression;
final String inverseColumnsTableExpression;
final List<String> identifyingColumnsList = new ArrayList<>();
if ( foreignKeyDescriptor.getDirection() == ForeignKeyDirection.FROM_PARENT && !referringPrimaryKey ) { if ( foreignKeyDescriptor.getDirection() == ForeignKeyDirection.FROM_PARENT && !referringPrimaryKey ) {
identifyingColumnsTableExpression = foreignKeyDescriptor.getTargetTableExpression(); identifyingColumnsTableExpression = foreignKeyDescriptor.getTargetTableExpression();
inverseColumnsTableExpression = foreignKeyDescriptor.getReferringTableExpression();
foreignKeyDescriptor.visitTargetColumns(
(containingTableExpression, columnExpression, jdbcMapping) -> {
identifyingColumnsList.add( containingTableExpression + "." + columnExpression );
}
);
} }
else { else {
identifyingColumnsTableExpression = foreignKeyDescriptor.getReferringTableExpression(); identifyingColumnsTableExpression = foreignKeyDescriptor.getReferringTableExpression();
inverseColumnsTableExpression = foreignKeyDescriptor.getTargetTableExpression();
foreignKeyDescriptor.visitReferringColumns(
(containingTableExpression, columnExpression, jdbcMapping) -> {
identifyingColumnsList.add( containingTableExpression + "." + columnExpression );
}
);
} }
this.identifyingColumns = identifyingColumnsList.toArray( new String[0] );
this.identifyingColumnsTableExpression = identifyingColumnsTableExpression; this.identifyingColumnsTableExpression = identifyingColumnsTableExpression;
this.inverseIdentifyingColumnsTableExpression = inverseColumnsTableExpression;
} }
public ForeignKeyDescriptor getForeignKeyDescriptor() { public ForeignKeyDescriptor getForeignKeyDescriptor() {
@ -188,11 +163,6 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
return navigableRole; return navigableRole;
} }
@Override
public String[] getIdentifyingColumnExpressions() {
return identifyingColumns;
}
@Override @Override
public Fetch resolveCircularFetch( public Fetch resolveCircularFetch(
NavigablePath fetchablePath, NavigablePath fetchablePath,
@ -218,7 +188,7 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
final Association associationParent = (Association) referencedModePart; final Association associationParent = (Association) referencedModePart;
if ( Arrays.equals( associationParent.getIdentifyingColumnExpressions(), this.getIdentifyingColumnExpressions() ) ) { if (foreignKeyDescriptor.equals( associationParent.getForeignKeyDescriptor() ) ) {
// we need to determine the NavigablePath referring to the entity that the bi-dir // we need to determine the NavigablePath referring to the entity that the bi-dir
// fetch will "return" for its Assembler. so we walk "up" the FetchParent graph // fetch will "return" for its Assembler. so we walk "up" the FetchParent graph
// to find the "referenced entity" reference // to find the "referenced entity" reference

View File

@ -52,14 +52,22 @@ public class Helper {
if ( ResultsLogger.INSTANCE.isDebugEnabled() ) { if ( ResultsLogger.INSTANCE.isDebugEnabled() ) {
return initializer -> { return initializer -> {
ResultsLogger.INSTANCE.debug( "Adding initializer : " + initializer ); ResultsLogger.INSTANCE.debug( "Adding initializer : " + initializer );
initializers.add( initializer ); addIfNotPresent( initializers, initializer );
}; };
} }
else { else {
return initializers::add; return initializer ->
addIfNotPresent( initializers, initializer );
} }
} }
private static void addIfNotPresent(List<Initializer> initializers, Initializer initializer) {
if ( initializers.contains( initializer ) ) {
return;
}
initializers.add( initializer );
}
public static void finalizeCollectionLoading( public static void finalizeCollectionLoading(
PersistenceContext persistenceContext, PersistenceContext persistenceContext,
CollectionPersister collectionDescriptor, CollectionPersister collectionDescriptor,

View File

@ -155,13 +155,6 @@ public class BiDirectionalFetchImpl implements BiDirectionalFetch, Association {
return ( (Association) fetchParent ).getForeignKeyDescriptor(); return ( (Association) fetchParent ).getForeignKeyDescriptor();
} }
@Override
public String[] getIdentifyingColumnExpressions() {
// fetch parent really always needs to be an Association, so we simply cast here
// should maybe verify this in ctor
return ( (Association) fetchParent ).getIdentifyingColumnExpressions();
}
@Override @Override
public Fetch generateFetch( public Fetch generateFetch(
FetchParent fetchParent, FetchParent fetchParent,