Implemented SingularAssociationAttributeMapping circular fetch detection for ToOne with JoinTable
This commit is contained in:
parent
2afd4c8123
commit
f3b2a1537b
|
@ -64,6 +64,10 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||||
|
|
||||||
void visitColumnMappings(FkColumnMappingConsumer consumer);
|
void visitColumnMappings(FkColumnMappingConsumer consumer);
|
||||||
|
|
||||||
|
<T> T visitColumnMapping(FkColumnMappingFunction<T> function);
|
||||||
|
|
||||||
|
// todo (6.0): the 2 interfaces does not take into account composite keys, referringColumn
|
||||||
|
// and targetColumn should be collections
|
||||||
interface FkColumnMappingConsumer {
|
interface FkColumnMappingConsumer {
|
||||||
void consume(
|
void consume(
|
||||||
String referringTable,
|
String referringTable,
|
||||||
|
@ -72,4 +76,14 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
||||||
String targetColumn,
|
String targetColumn,
|
||||||
JdbcMapping jdbcMapping);
|
JdbcMapping jdbcMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface FkColumnMappingFunction<T> {
|
||||||
|
T apply(
|
||||||
|
String referringTable,
|
||||||
|
String referringColumn,
|
||||||
|
String targetTable,
|
||||||
|
String targetColumn,
|
||||||
|
JdbcMapping jdbcMapping);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -296,6 +296,17 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
consumer.accept( targetColumnContainingTable, targetColumnExpression, jdbcMapping );
|
consumer.accept( targetColumnContainingTable, targetColumnExpression, jdbcMapping );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T visitColumnMapping(FkColumnMappingFunction<T> function) {
|
||||||
|
return function.apply(
|
||||||
|
keyColumnContainingTable,
|
||||||
|
keyColumnExpression ,
|
||||||
|
targetColumnContainingTable,
|
||||||
|
targetColumnExpression ,
|
||||||
|
jdbcMapping
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void visitColumnMappings(FkColumnMappingConsumer consumer) {
|
public void visitColumnMappings(FkColumnMappingConsumer consumer) {
|
||||||
consumer.consume(
|
consumer.consume(
|
||||||
|
|
|
@ -12,6 +12,7 @@ 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.engine.FetchStrategy;
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.engine.FetchTiming;
|
import org.hibernate.engine.FetchTiming;
|
||||||
import org.hibernate.mapping.ManyToOne;
|
import org.hibernate.mapping.ManyToOne;
|
||||||
|
@ -26,6 +27,7 @@ import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.persister.entity.SingleTableEntityPersister;
|
||||||
import org.hibernate.property.access.spi.PropertyAccess;
|
import org.hibernate.property.access.spi.PropertyAccess;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||||
|
@ -208,16 +210,62 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FetchParent associationParent = fetchParent.resolveContainingAssociationParent();
|
final FetchParent associationFetchParent = fetchParent.resolveContainingAssociationParent();
|
||||||
assert associationParent.getReferencedModePart() instanceof Association;
|
assert associationFetchParent.getReferencedModePart() instanceof Association;
|
||||||
|
|
||||||
final Association association = (Association) associationParent.getReferencedModePart();
|
final Association associationParent = (Association) associationFetchParent.getReferencedModePart();
|
||||||
|
|
||||||
if ( Arrays.equals( association.getIdentifyingColumnExpressions(), this.getIdentifyingColumnExpressions() ) ) {
|
if ( Arrays.equals( associationParent.getIdentifyingColumnExpressions(), this.getIdentifyingColumnExpressions() ) ) {
|
||||||
// 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
|
||||||
|
|
||||||
|
return createBiDirectionalFetch( fetchablePath, fetchParent );
|
||||||
|
}
|
||||||
|
|
||||||
|
// this is the case of a JoinTable
|
||||||
|
// PARENT(id)
|
||||||
|
// PARENT_CHILD(parent_id, child_id)
|
||||||
|
// CHILD(id)
|
||||||
|
// the FKDescriptor for the association `Parent.child` will be
|
||||||
|
// PARENT_CHILD.child.id -> CHILD.id
|
||||||
|
// and the FKDescriptor for the association `Child.parent` will be
|
||||||
|
// PARENT_CHILD.parent.id -> PARENT.id
|
||||||
|
// in such a case the associationParent.getIdentifyingColumnExpressions() is PARENT_CHILD.parent_id
|
||||||
|
// while the getIdentifyingColumnExpressions for this association is PARENT_CHILD.child_id
|
||||||
|
// so we will check if the parentAssociation ForeignKey Target match with the association entity identifier table and columns
|
||||||
|
final ForeignKeyDescriptor associationParentForeignKeyDescriptor = associationParent.getForeignKeyDescriptor();
|
||||||
|
if ( this.foreignKeyDescriptor.getReferringTableExpression().equals( associationParentForeignKeyDescriptor
|
||||||
|
.getReferringTableExpression() ) ) {
|
||||||
|
final SingleTableEntityPersister entityPersister = (SingleTableEntityPersister) getDeclaringType();
|
||||||
|
if ( associationParentForeignKeyDescriptor.getTargetTableExpression()
|
||||||
|
.equals( entityPersister.getTableName() ) ) {
|
||||||
|
final String[] identifierColumnNames = entityPersister.getIdentifierColumnNames();
|
||||||
|
return associationParentForeignKeyDescriptor.visitColumnMapping( (referringTable, referringColumns, targetTable, targetColumns, jdbcMapping) -> {
|
||||||
|
// if ( identifierColumnNames.length == targetColumns.size() ) {
|
||||||
|
// for ( int i = 0; i < identifierColumnNames.length; i++ ) {
|
||||||
|
// if ( !targetColumns.contains( identifierColumnNames[i] ) ) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if ( identifierColumnNames.length > 1 ) {
|
||||||
|
throw new NotYetImplementedFor6Exception(
|
||||||
|
"Support for composite foreign -keys not yet implemented" );
|
||||||
|
}
|
||||||
|
if ( targetColumns.equals( identifierColumnNames[0] ) ) {
|
||||||
|
return createBiDirectionalFetch( fetchablePath, fetchParent );
|
||||||
|
}
|
||||||
|
// }
|
||||||
|
return null;
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Fetch createBiDirectionalFetch(NavigablePath fetchablePath, FetchParent fetchParent) {
|
||||||
final EntityResultGraphNode referencedEntityReference = resolveEntityGraphNode( fetchParent );
|
final EntityResultGraphNode referencedEntityReference = resolveEntityGraphNode( fetchParent );
|
||||||
|
|
||||||
if ( referencedEntityReference == null ) {
|
if ( referencedEntityReference == null ) {
|
||||||
|
@ -235,9 +283,6 @@ public class SingularAssociationAttributeMapping extends AbstractSingularAttribu
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected EntityResultGraphNode resolveEntityGraphNode(FetchParent fetchParent) {
|
protected EntityResultGraphNode resolveEntityGraphNode(FetchParent fetchParent) {
|
||||||
FetchParent processingParent = fetchParent;
|
FetchParent processingParent = fetchParent;
|
||||||
while ( processingParent != null ) {
|
while ( processingParent != null ) {
|
||||||
|
|
Loading…
Reference in New Issue