diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java index 218291d8bc..05e46bf437 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/tree/select/SqmQuerySpec.java @@ -28,6 +28,7 @@ import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmNode; import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath; +import org.hibernate.query.sqm.tree.domain.SqmTreatedPath; import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef; import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.from.SqmAttributeJoin; @@ -588,12 +589,14 @@ public class SqmQuerySpec extends SqmQueryPart sb.append( root.getCorrelationParent().resolveAlias() ); sb.append( ' ' ).append( root.resolveAlias() ); appendJoins( root, sb ); + appendTreatJoins( root, sb ); } } else { sb.append( root.getEntityName() ); sb.append( ' ' ).append( root.resolveAlias() ); appendJoins( root, sb ); + appendTreatJoins( root, sb ); } separator = ", "; } @@ -639,8 +642,16 @@ public class SqmQuerySpec extends SqmQueryPart } if ( sqmJoin instanceof SqmAttributeJoin ) { final SqmAttributeJoin attributeJoin = (SqmAttributeJoin) sqmJoin; - sb.append( sqmFrom.resolveAlias() ).append( '.' ); - sb.append( ( attributeJoin ).getAttribute().getName() ); + if ( sqmFrom instanceof SqmTreatedPath ) { + final SqmTreatedPath treatedPath = (SqmTreatedPath) sqmFrom; + sb.append( "treat(" ); + sb.append( treatedPath.getWrappedPath().resolveAlias() ); + sb.append( " as " ).append( treatedPath.getTreatTarget().getName() ).append( ')' ); + } + else { + sb.append( sqmFrom.resolveAlias() ); + } + sb.append( '.' ).append( ( attributeJoin ).getAttribute().getName() ); sb.append( ' ' ).append( sqmJoin.resolveAlias() ); if ( attributeJoin.getJoinPredicate() != null ) { sb.append( " on " ); @@ -681,4 +692,10 @@ public class SqmQuerySpec extends SqmQueryPart separator = ", "; } } + + private void appendTreatJoins(SqmFrom sqmFrom, StringBuilder sb) { + for ( SqmFrom sqmTreat : sqmFrom.getSqmTreats() ) { + appendJoins( sqmTreat, sb ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java index 7d0179726c..0d43356a96 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/query/ToHqlStringTest.java @@ -4,20 +4,32 @@ import org.hibernate.query.spi.SqmQuery; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.orm.junit.EntityManagerFactoryScope; +import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.Jpa; import org.junit.jupiter.api.Test; import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; import jakarta.persistence.Query; import jakarta.persistence.TypedQuery; import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Expression; +import jakarta.persistence.criteria.Join; import jakarta.persistence.criteria.Root; +import org.hamcrest.CoreMatchers; +import org.hamcrest.MatcherAssert; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.MatcherAssert.assertThat; @Jpa( - annotatedClasses = ToHqlStringTest.TestEntity.class + annotatedClasses = { + ToHqlStringTest.TestEntity.class, + ToHqlStringTest.TestEntitySub.class + } ) @TestForIssue( jiraKey = "HHH-15389") public class ToHqlStringTest { @@ -60,6 +72,27 @@ public class ToHqlStringTest { ); } + @Test + @JiraKey( "HHH-16676" ) + public void testCriteriaWithTreatToHqlString(EntityManagerFactoryScope scope) { + scope.inTransaction( + entityManager -> { + CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + CriteriaQuery criteriaQuery = builder.createQuery( Object.class ); + + Root root = criteriaQuery.from( TestEntity.class ); + Join entity = builder.treat( root, TestEntitySub.class ).join( "entity" ); + criteriaQuery = criteriaQuery.select( entity ); + + TypedQuery query = entityManager.createQuery( criteriaQuery ); + String hqlString = ( (SqmQuery) query ).getSqmStatement().toHqlString(); + final int fromIndex = hqlString.indexOf( " from " ); + final String alias = hqlString.substring( "select ".length(), fromIndex ); + assertThat( hqlString.substring( fromIndex ), containsString( alias ) ); + } + ); + } + public static class TestDto { @Id public Integer id; @@ -74,4 +107,10 @@ public class ToHqlStringTest { public String name; } + + @Entity(name = "TestEntitySub") + public static class TestEntitySub extends TestEntity { + @ManyToOne(fetch = FetchType.LAZY) + TestEntity entity; + } }