HHH-16382 Make sure joins are adapted to inner if non-FK parts of a path are de-referenced
This commit is contained in:
parent
991ea65c7c
commit
eb82b2f390
|
@ -3406,23 +3406,30 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
||||||
registerTreatUsage( (SqmFrom<?, ?>) parentPath, tableGroup );
|
registerTreatUsage( (SqmFrom<?, ?>) parentPath, tableGroup );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( getCurrentClauseStack().getCurrent() != Clause.SELECT
|
if ( parentPath instanceof SqmSimplePath<?>
|
||||||
|
&& CollectionPart.Nature.fromName( parentPath.getNavigablePath().getLocalName() ) == null
|
||||||
|
&& getCurrentClauseStack().getCurrent() != Clause.SELECT
|
||||||
&& parentPath.getParentPath() != null
|
&& parentPath.getParentPath() != null
|
||||||
&& tableGroup.getModelPart() instanceof ToOneAttributeMapping ) {
|
&& tableGroup.getModelPart() instanceof ToOneAttributeMapping ) {
|
||||||
// we need to handle the case of an implicit path involving a to-one
|
// we need to handle the case of an implicit path involving a to-one
|
||||||
// association with not-found mapping where that path has been previously
|
// association that path has been previously joined using left.
|
||||||
// joined using left. typically, this indicates that the to-one is being
|
// typically, this indicates that the to-one is being
|
||||||
// fetched - the fetch would use a left-join. however, since the path is
|
// fetched - the fetch would use a left-join. however, since the path is
|
||||||
// used outside the select-clause also, we need to force the join to be inner
|
// used outside the select-clause also, we need to force the join to be inner
|
||||||
final ToOneAttributeMapping toOneMapping = (ToOneAttributeMapping) tableGroup.getModelPart();
|
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) tableGroup.getModelPart();
|
||||||
if ( toOneMapping.hasNotFoundAction() ) {
|
final String partName = sqmPath.getResolvedModel().getPathName();
|
||||||
|
final ModelPart pathPart;
|
||||||
|
if ( !toOneAttributeMapping.isFkOptimizationAllowed()
|
||||||
|
|| !( ( pathPart = toOneAttributeMapping.findSubPart( partName ) ) instanceof ValuedModelPart )
|
||||||
|
|| !toOneAttributeMapping.getForeignKeyDescriptor().isKeyPart( (ValuedModelPart) pathPart ) ) {
|
||||||
final NavigablePath parentParentPath = parentPath.getParentPath().getNavigablePath();
|
final NavigablePath parentParentPath = parentPath.getParentPath().getNavigablePath();
|
||||||
final TableGroup parentParentTableGroup = fromClauseIndex.findTableGroup( parentParentPath );
|
final TableGroup parentParentTableGroup = fromClauseIndex.findTableGroup( parentParentPath );
|
||||||
parentParentTableGroup.visitTableGroupJoins( (join) -> {
|
final TableGroupJoin tableGroupJoin = parentParentTableGroup.findTableGroupJoin( tableGroup );
|
||||||
if ( join.getNavigablePath().equals( parentPath.getNavigablePath() ) && join.isImplicit() ) {
|
// We might get null here if the parentParentTableGroup is correlated and tableGroup is from the outer query
|
||||||
join.setJoinType( SqlAstJoinType.INNER );
|
// In this case, we don't want to override the join type, though it is debatable if it's ok to reuse a join in this case
|
||||||
|
if ( tableGroupJoin != null ) {
|
||||||
|
tableGroupJoin.setJoinType( SqlAstJoinType.INNER );
|
||||||
}
|
}
|
||||||
} );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
package org.hibernate.orm.test.annotations.onetoone;
|
package org.hibernate.orm.test.annotations.onetoone;
|
||||||
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||||
import jakarta.persistence.criteria.CriteriaQuery;
|
import jakarta.persistence.criteria.CriteriaQuery;
|
||||||
|
@ -27,6 +28,10 @@ import org.hibernate.orm.test.annotations.Customer;
|
||||||
import org.hibernate.orm.test.annotations.Discount;
|
import org.hibernate.orm.test.annotations.Discount;
|
||||||
import org.hibernate.orm.test.annotations.Passport;
|
import org.hibernate.orm.test.annotations.Passport;
|
||||||
import org.hibernate.orm.test.annotations.Ticket;
|
import org.hibernate.orm.test.annotations.Ticket;
|
||||||
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
|
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||||
|
import org.hibernate.query.criteria.JpaRoot;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
@ -417,6 +422,36 @@ public class OneToOneTest extends BaseNonConfigCoreFunctionalTestCase {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDereferenceOneToOne() {
|
||||||
|
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
||||||
|
Client c1 = new Client();
|
||||||
|
c1.setName( "C1" );
|
||||||
|
Client c2 = new Client();
|
||||||
|
c2.setName( "C2" );
|
||||||
|
Client c3 = new Client();
|
||||||
|
c3.setName( "C3" );
|
||||||
|
Address a = new Address();
|
||||||
|
a.setCity( "Vienna" );
|
||||||
|
c1.setAddress( a );
|
||||||
|
c3.setAddress( new Address() );
|
||||||
|
session.persist( c1 );
|
||||||
|
session.persist( c2 );
|
||||||
|
session.persist( c3 );
|
||||||
|
} );
|
||||||
|
|
||||||
|
TransactionUtil.doInHibernate( this::sessionFactory, session -> {
|
||||||
|
HibernateCriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
|
JpaCriteriaQuery<Client> query = cb.createQuery( Client.class );
|
||||||
|
JpaRoot<Client> root = query.from( Client.class );
|
||||||
|
query.where( root.get( "address" ).get( "city" ).isNull() );
|
||||||
|
List<Client> resultList = session.createQuery( query ).getResultList();
|
||||||
|
|
||||||
|
assertEquals( 1, resultList.size() );
|
||||||
|
assertEquals( "C3", resultList.get( 0 ).getName() );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Class[] getAnnotatedClasses() {
|
protected Class[] getAnnotatedClasses() {
|
||||||
return new Class[] {
|
return new Class[] {
|
||||||
|
|
Loading…
Reference in New Issue