Fix foreign key direction issues

This commit is contained in:
Christian Beikov 2021-05-06 16:54:47 +02:00
parent 0157af79f7
commit e122ac33dc
6 changed files with 36 additions and 52 deletions

View File

@ -90,6 +90,7 @@ import org.hibernate.type.CollectionType;
import org.hibernate.type.ComponentType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.EntityType;
import org.hibernate.type.ForeignKeyDirection;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -969,8 +970,10 @@ public class MappingModelCreationHelper {
.getEntityPersister( bootValueMapping.getReferencedEntityName() );
String referencedPropertyName;
boolean swapDirection = false;
if ( bootValueMapping instanceof OneToOne ) {
OneToOne oneToOne = (OneToOne) bootValueMapping;
swapDirection = oneToOne.getForeignKeyType() == ForeignKeyDirection.TO_PARENT;
referencedPropertyName = oneToOne.getMappedByProperty();
if ( referencedPropertyName == null ) {
referencedPropertyName = oneToOne.getReferencedPropertyName();
@ -1054,7 +1057,8 @@ public class MappingModelCreationHelper {
keySelectableMapping,
simpleFkTarget,
(owner) -> ( (PropertyBasedMapping) simpleFkTarget ).getPropertyAccess().getGetter().get( owner ),
bootValueMapping.isReferenceToPrimaryKey()
bootValueMapping.isReferenceToPrimaryKey(),
swapDirection
);
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
}
@ -1062,6 +1066,7 @@ public class MappingModelCreationHelper {
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor(
(EmbeddableValuedModelPart) fkTarget,
bootValueMapping,
swapDirection,
dialect,
creationProcess
);

View File

@ -68,12 +68,31 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
BasicValuedModelPart targetModelPart,
Function<Object, Object> disassemblyValueExtractor,
boolean refersToPrimaryKey) {
this( keySelectableMapping, targetModelPart, disassemblyValueExtractor, refersToPrimaryKey, false );
}
public SimpleForeignKeyDescriptor(
SelectableMapping keySelectableMapping,
BasicValuedModelPart targetModelPart,
Function<Object, Object> disassemblyValueExtractor,
boolean refersToPrimaryKey,
boolean swapDirection) {
assert keySelectableMapping != null;
assert targetModelPart != null;
assert disassemblyValueExtractor != null;
this.keySide = BasicAttributeMapping.withSelectableMapping( targetModelPart, keySelectableMapping );
this.targetSide = targetModelPart;
final BasicValuedModelPart keyModelPart = BasicAttributeMapping.withSelectableMapping(
targetModelPart,
keySelectableMapping
);
if ( swapDirection ) {
this.keySide = targetModelPart;
this.targetSide = keyModelPart;
}
else {
this.keySide = keyModelPart;
this.targetSide = targetModelPart;
}
this.disassemblyValueExtractor = disassemblyValueExtractor;
this.refersToPrimaryKey = refersToPrimaryKey;
}

View File

@ -646,7 +646,7 @@ public class ToOneAttributeMapping
else {
// case 1.1
keyResult = foreignKeyDescriptor.createDomainResult( fetchablePath, parentTableGroup, isKeyReferringSide, creationState );
selectByUniqueKey = true;
selectByUniqueKey = bidirectionalAttributeName != null;
}
if ( fetchTiming == FetchTiming.IMMEDIATE ) {

View File

@ -10,6 +10,7 @@ import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AbstractFetchParent;
@ -67,7 +68,7 @@ public class EmbeddableForeignKeyResultImpl<T>
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) fetchable;
shouldSelect = selected && !creationState.isAssociationKeyVisited(
toOne.getForeignKeyDescriptor().getAssociationKey()
);
) && !ForeignKeyDescriptor.PART_NAME.equals( getNavigablePath().getLocalName() );
}
else {
shouldSelect = selected;

View File

@ -64,56 +64,14 @@ public class EagerKeyManyToOneTest {
scope.inTransaction(
session -> {
try {
/*
select
card0_.id as id1_0_0_,
card0_.field_card_id as field_ca2_0_0_,
card0_."field_key_id" as field_ke3_0_0_,
cardfield1_.card_id as card_id1_1_1_,
cardfield1_."key_id" as key_id2_1_1_,
card2_.id as id1_0_2_,
card2_.field_card_id as field_ca2_0_2_,
card2_."field_key_id" as field_ke3_0_2_,
key3_.id as id1_2_3_
from
Card card0_
left outer join
CardField cardfield1_
on card0_.field_card_id=cardfield1_.card_id
and card0_."field_key_id"=cardfield1_."key_id"
left outer join
Card card2_
on cardfield1_.card_id=card2_.id
left outer join
"key" key3_
on cardfield1_."key_id"=key3_.id
where
card0_.id=?
11:08:42,367 TRACE BasicBinder:64 - binding parameter [1] as [VARCHAR] - [cardId]
11:08:42,370 TRACE BasicExtractor:60 - extracted value ([id1_0_2_] : [VARCHAR]) - [cardId]
11:08:42,370 TRACE BasicExtractor:60 - extracted value ([id1_2_3_] : [VARCHAR]) - [keyId]
11:08:42,370 TRACE BasicExtractor:60 - extracted value ([card_id1_1_1_] : [VARCHAR]) - [cardId]
11:08:42,370 TRACE BasicExtractor:60 - extracted value ([key_id2_1_1_] : [VARCHAR]) - [keyId]
11:08:42,371 TRACE BasicExtractor:60 - extracted value ([field_ca2_0_2_] : [VARCHAR]) - [cardId]
11:08:42,372 TRACE BasicExtractor:60 - extracted value ([field_ke3_0_2_] : [VARCHAR]) - [keyId]
11:08:42,372 DEBUG SQL:144 -
select
key0_.id as id1_2_0_
from
"key" key0_
where
key0_.id=?
11:08:42,372 TRACE BasicBinder:64 - binding parameter [1] as [VARCHAR] - [keyId]
*/
Card card = session.get( Card.class, CARD_ID );
CardField cf = card.getField();
assertSame( card, cf.getPrimaryKey().getCard() );
statementInspector.assertExecutedCount( 2 );
// Since CardField and Key have no additional state, it's not necessary to join their tables
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
// Since Key have no additional state, it's not necessary to join their tables
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 2 );
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
}
catch (StackOverflowError soe) {

View File

@ -82,7 +82,7 @@ public class LazyManyToOneEmbeddedIdWithToOneFKTest {
System system = session.get( System.class, 1 );
assertThat( system, is( notNullValue() ) );
statementInspector.assertExecutedCount( 1 );
statementInspector.assertExecutedCount( 2 );
assertThat( system.getId(), is( 1 ) );
@ -98,8 +98,9 @@ public class LazyManyToOneEmbeddedIdWithToOneFKTest {
SystemUser user = system.getUser();
assertThat( user, is( notNullValue() ) );
statementInspector.assertExecutedCount( 1 );
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 1 );
statementInspector.assertExecutedCount( 2 );
statementInspector.assertNumberOfOccurrenceInQuery( 0, "join", 0 );
statementInspector.assertNumberOfOccurrenceInQuery( 1, "join", 0 );
statementInspector.clear();
assertThat( user.getName(), is( "Fab" ) );