initial working "unqualified" entity join support in criteria
This commit is contained in:
parent
26b08fd35e
commit
233a3b176c
|
@ -49,7 +49,9 @@ import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||||
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||||
import org.hibernate.stat.spi.StatisticsImplementor;
|
import org.hibernate.stat.spi.StatisticsImplementor;
|
||||||
import org.hibernate.type.Type;
|
import org.hibernate.type.Type;
|
||||||
|
@ -409,7 +411,7 @@ public class SessionFactoryDelegatingImpl implements SessionFactoryImplementor,
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CriteriaBuilder getCriteriaBuilder() {
|
public HibernateCriteriaBuilder getCriteriaBuilder() {
|
||||||
return delegate.getCriteriaBuilder();
|
return delegate.getCriteriaBuilder();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.persistence.EntityGraph;
|
import javax.persistence.EntityGraph;
|
||||||
import javax.persistence.criteria.CriteriaBuilder;
|
|
||||||
|
|
||||||
import org.hibernate.CustomEntityDirtinessStrategy;
|
import org.hibernate.CustomEntityDirtinessStrategy;
|
||||||
import org.hibernate.EntityNameResolver;
|
import org.hibernate.EntityNameResolver;
|
||||||
|
@ -37,6 +36,7 @@ import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||||
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
|
import org.hibernate.query.spi.QueryParameterBindingTypeResolver;
|
||||||
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
import org.hibernate.query.sqm.spi.SqmCreationContext;
|
||||||
|
@ -88,7 +88,7 @@ public interface SessionFactoryImplementor
|
||||||
QueryEngine getQueryEngine();
|
QueryEngine getQueryEngine();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
CriteriaBuilder getCriteriaBuilder();
|
HibernateCriteriaBuilder getCriteriaBuilder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
SessionBuilderImplementor withOptions();
|
SessionBuilderImplementor withOptions();
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.query.criteria;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface JpaEntityJoin<T> extends JpaJoinedFrom<T,T> {
|
||||||
|
@Override
|
||||||
|
EntityDomainType<T> getModel();
|
||||||
|
}
|
|
@ -19,7 +19,7 @@ import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface JpaJoin<O, T> extends JpaFrom<O, T>, Join<O, T> {
|
public interface JpaJoin<O, T> extends JpaJoinedFrom<O, T>, Join<O, T> {
|
||||||
@Override
|
@Override
|
||||||
PersistentAttribute<? super O, ?> getAttribute();
|
PersistentAttribute<? super O, ?> getAttribute();
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.query.criteria;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exists within the hierarchy mainly to support "entity joins".
|
||||||
|
*
|
||||||
|
* @see JpaEntityJoin
|
||||||
|
* @see org.hibernate.query.sqm.tree.from.SqmEntityJoin
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface JpaJoinedFrom<O,T> extends JpaFrom<O, T> {
|
||||||
|
}
|
|
@ -18,4 +18,8 @@ public interface JpaRoot<T> extends JpaFrom<T,T>, Root<T> {
|
||||||
EntityDomainType<T> getModel();
|
EntityDomainType<T> getModel();
|
||||||
|
|
||||||
EntityDomainType<T> getManagedType();
|
EntityDomainType<T> getManagedType();
|
||||||
|
|
||||||
|
<X> JpaEntityJoin<X> join(Class<X> entityJavaType);
|
||||||
|
|
||||||
|
<X> JpaEntityJoin<X> join(EntityDomainType<X> entity);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,10 @@ package org.hibernate.query.sqm;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class InterpretationException extends RuntimeException {
|
public class InterpretationException extends RuntimeException {
|
||||||
|
public InterpretationException(String query) {
|
||||||
|
this( query, null );
|
||||||
|
}
|
||||||
|
|
||||||
public InterpretationException(String query, Throwable cause) {
|
public InterpretationException(String query, Throwable cause) {
|
||||||
super(
|
super(
|
||||||
"Error interpreting query [" + query + "]; this may indicate a semantic (user query) problem or a bug in the parser",
|
"Error interpreting query [" + query + "]; this may indicate a semantic (user query) problem or a bug in the parser",
|
||||||
|
|
|
@ -10,6 +10,7 @@ import javax.persistence.metamodel.Bindable;
|
||||||
|
|
||||||
import org.hibernate.NotYetImplementedFor6Exception;
|
import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.Queryable;
|
import org.hibernate.metamodel.mapping.Queryable;
|
||||||
|
@ -29,7 +30,9 @@ import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.query.sqm.SqmExpressable;
|
import org.hibernate.query.sqm.SqmExpressable;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.sqm.SqmTreeTransformationLogger;
|
import org.hibernate.query.sqm.SqmTreeTransformationLogger;
|
||||||
|
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
|
||||||
import org.hibernate.query.sqm.sql.SqlAstCreationState;
|
import org.hibernate.query.sqm.sql.SqlAstCreationState;
|
||||||
|
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||||
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
import org.hibernate.query.sqm.tree.SqmTypedNode;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||||
|
@ -166,4 +169,15 @@ public class SqmMappingModelHelper {
|
||||||
|
|
||||||
return tableGroup;
|
return tableGroup;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static EntityMappingType resolveExplicitTreatTarget(
|
||||||
|
SqmPath<?> sqmPath,
|
||||||
|
SqmToSqlAstConverter converter) {
|
||||||
|
if ( sqmPath instanceof SqmTreatedPath ) {
|
||||||
|
final SqmTreatedPath treatedPath = (SqmTreatedPath) sqmPath;
|
||||||
|
return resolveEntityPersister( treatedPath.getTreatTarget(), converter.getCreationContext().getSessionFactory() );
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,9 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
||||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
import org.hibernate.internal.util.collections.Stack;
|
import org.hibernate.internal.util.collections.Stack;
|
||||||
import org.hibernate.internal.util.collections.StandardStack;
|
import org.hibernate.internal.util.collections.StandardStack;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.BinaryArithmeticOperator;
|
import org.hibernate.query.BinaryArithmeticOperator;
|
||||||
|
@ -31,6 +31,7 @@ import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.query.spi.QueryParameterBinding;
|
import org.hibernate.query.spi.QueryParameterBinding;
|
||||||
import org.hibernate.query.spi.QueryParameterBindings;
|
import org.hibernate.query.spi.QueryParameterBindings;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
|
import org.hibernate.query.sqm.InterpretationException;
|
||||||
import org.hibernate.query.sqm.SqmExpressable;
|
import org.hibernate.query.sqm.SqmExpressable;
|
||||||
import org.hibernate.query.sqm.SqmPathSource;
|
import org.hibernate.query.sqm.SqmPathSource;
|
||||||
import org.hibernate.query.sqm.function.SqmFunction;
|
import org.hibernate.query.sqm.function.SqmFunction;
|
||||||
|
@ -67,6 +68,7 @@ import org.hibernate.query.sqm.tree.from.SqmCrossJoin;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
|
import org.hibernate.query.sqm.tree.from.SqmEntityJoin;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmFromClause;
|
import org.hibernate.query.sqm.tree.from.SqmFromClause;
|
||||||
|
import org.hibernate.query.sqm.tree.from.SqmJoin;
|
||||||
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
import org.hibernate.query.sqm.tree.from.SqmRoot;
|
||||||
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
import org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement;
|
||||||
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
|
import org.hibernate.query.sqm.tree.predicate.SqmAndPredicate;
|
||||||
|
@ -407,14 +409,7 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
currentClauseStack.push( Clause.FROM );
|
currentClauseStack.push( Clause.FROM );
|
||||||
|
|
||||||
try {
|
try {
|
||||||
sqmFromClause.visitRoots(
|
sqmFromClause.visitRoots( this::consumeFromClauseRoot );
|
||||||
sqmRoot -> {
|
|
||||||
final TableGroup rootTableGroup = visitRootPath( sqmRoot );
|
|
||||||
|
|
||||||
currentQuerySpec().getFromClause().addRoot( rootTableGroup );
|
|
||||||
getFromClauseIndex().register( sqmRoot, rootTableGroup );
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
currentClauseStack.pop();
|
currentClauseStack.pop();
|
||||||
|
@ -423,16 +418,11 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
protected void consumeFromClauseRoot(SqmRoot<?> sqmRoot) {
|
||||||
|
log.tracef( "Resolving SqmRoot [%s] to TableGroup", sqmRoot );
|
||||||
|
|
||||||
@Override
|
assert ! fromClauseIndex.isResolved( sqmRoot );
|
||||||
public TableGroup visitRootPath(SqmRoot<?> sqmRoot) {
|
|
||||||
log.tracef( "Starting resolution of SqmRoot [%s] to TableGroup", sqmRoot );
|
|
||||||
|
|
||||||
final TableGroup resolvedTableGroup = fromClauseIndex.findTableGroup( sqmRoot.getNavigablePath() );
|
|
||||||
if ( resolvedTableGroup != null ) {
|
|
||||||
log.tracef( "SqmRoot [%s] resolved to existing TableGroup [%s]", sqmRoot, resolvedTableGroup );
|
|
||||||
return resolvedTableGroup;
|
|
||||||
}
|
|
||||||
|
|
||||||
final EntityPersister entityDescriptor = resolveEntityPersister( sqmRoot.getReferencedPathSource() );
|
final EntityPersister entityDescriptor = resolveEntityPersister( sqmRoot.getReferencedPathSource() );
|
||||||
|
|
||||||
|
@ -446,108 +436,180 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
fromClauseIndex.register( sqmRoot, tableGroup );
|
|
||||||
|
|
||||||
log.tracef( "Resolved SqmRoot [%s] to new TableGroup [%s]", sqmRoot, tableGroup );
|
log.tracef( "Resolved SqmRoot [%s] to new TableGroup [%s]", sqmRoot, tableGroup );
|
||||||
|
|
||||||
visitExplicitJoins( sqmRoot, tableGroup );
|
fromClauseIndex.register( sqmRoot, tableGroup );
|
||||||
visitImplicitJoins( sqmRoot, tableGroup );
|
currentQuerySpec().getFromClause().addRoot( tableGroup );
|
||||||
|
|
||||||
return tableGroup;
|
consumeExplicitJoins( sqmRoot, tableGroup );
|
||||||
|
consumeImplicitJoins( sqmRoot, tableGroup );
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityPersister resolveEntityPersister(EntityDomainType<?> entityDomainType) {
|
private EntityPersister resolveEntityPersister(EntityDomainType<?> entityDomainType) {
|
||||||
return creationContext.getDomainModel().getEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
return creationContext.getDomainModel().getEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitExplicitJoins(SqmFrom<?,?> sqmFrom, TableGroup tableGroup) {
|
protected void consumeExplicitJoins(SqmFrom<?,?> sqmFrom, TableGroup lhsTableGroup) {
|
||||||
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
|
log.tracef( "Visiting explicit joins for `%s`", sqmFrom.getNavigablePath() );
|
||||||
|
|
||||||
sqmFrom.visitSqmJoins(
|
sqmFrom.visitSqmJoins(
|
||||||
sqmJoin -> {
|
sqmJoin -> consumeExplicitJoin( sqmJoin, lhsTableGroup )
|
||||||
final TableGroupJoin tableGroupJoin = (TableGroupJoin) sqmJoin.accept( this );
|
|
||||||
if ( tableGroupJoin != null ) {
|
|
||||||
tableGroup.addTableGroupJoin( tableGroupJoin );
|
|
||||||
getFromClauseIndex().register( sqmFrom, tableGroup );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void visitImplicitJoins(SqmPath<?> sqmPath, TableGroup tableGroup) {
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
protected void consumeExplicitJoin(SqmJoin<?,?> sqmJoin, TableGroup lhsTableGroup) {
|
||||||
|
if ( sqmJoin instanceof SqmAttributeJoin ) {
|
||||||
|
consumeAttributeJoin( ( (SqmAttributeJoin) sqmJoin ), lhsTableGroup );
|
||||||
|
}
|
||||||
|
else if ( sqmJoin instanceof SqmCrossJoin ) {
|
||||||
|
consumeCrossJoin( ( (SqmCrossJoin) sqmJoin ), lhsTableGroup );
|
||||||
|
}
|
||||||
|
else if ( sqmJoin instanceof SqmEntityJoin ) {
|
||||||
|
consumeEntityJoin( ( (SqmEntityJoin) sqmJoin ), lhsTableGroup );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new InterpretationException( "Could not resolve SqmJoin [" + sqmJoin.getNavigablePath() + "] to TableGroupJoin" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consumeAttributeJoin(SqmAttributeJoin<?,?> sqmJoin, TableGroup lhsTableGroup) {
|
||||||
|
assert fromClauseIndex.findTableGroup( sqmJoin.getNavigablePath() ) == null;
|
||||||
|
assert fromClauseIndex.findTableGroupJoin( sqmJoin.getNavigablePath() ) == null;
|
||||||
|
|
||||||
|
final SqmPathSource<?> pathSource = sqmJoin.getReferencedPathSource();
|
||||||
|
|
||||||
|
final AttributeMapping attributeMapping = (AttributeMapping) lhsTableGroup.getModelPart().findSubPart(
|
||||||
|
pathSource.getPathName(),
|
||||||
|
SqmMappingModelHelper.resolveExplicitTreatTarget( sqmJoin, this )
|
||||||
|
);
|
||||||
|
|
||||||
|
assert attributeMapping instanceof TableGroupJoinProducer;
|
||||||
|
final TableGroupJoin tableGroupJoin = ( (TableGroupJoinProducer) attributeMapping ).createTableGroupJoin(
|
||||||
|
sqmJoin.getNavigablePath(),
|
||||||
|
lhsTableGroup,
|
||||||
|
sqmJoin.getExplicitAlias(),
|
||||||
|
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
||||||
|
determineLockMode( sqmJoin.getExplicitAlias() ),
|
||||||
|
sqlAliasBaseManager, getSqlExpressionResolver(),
|
||||||
|
creationContext
|
||||||
|
);
|
||||||
|
|
||||||
|
fromClauseIndex.register( sqmJoin, tableGroupJoin );
|
||||||
|
|
||||||
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
||||||
|
// add any additional join restrictions
|
||||||
|
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||||
|
tableGroupJoin.applyPredicate(
|
||||||
|
(Predicate) sqmJoin.getJoinPredicate().accept( this )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
|
consumeImplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consumeCrossJoin(SqmCrossJoin sqmJoin, TableGroup lhsTableGroup) {
|
||||||
|
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
||||||
|
|
||||||
|
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(
|
||||||
|
sqmJoin.getNavigablePath(),
|
||||||
|
sqmJoin.getExplicitAlias(),
|
||||||
|
JoinType.CROSS,
|
||||||
|
determineLockMode( sqmJoin.getExplicitAlias() ),
|
||||||
|
sqlAliasBaseManager,
|
||||||
|
getSqlExpressionResolver(),
|
||||||
|
getCreationContext()
|
||||||
|
);
|
||||||
|
|
||||||
|
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||||
|
sqmJoin.getNavigablePath(),
|
||||||
|
JoinType.CROSS,
|
||||||
|
tableGroup
|
||||||
|
);
|
||||||
|
|
||||||
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
||||||
|
fromClauseIndex.register( sqmJoin, tableGroup );
|
||||||
|
|
||||||
|
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
|
consumeImplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consumeEntityJoin(SqmEntityJoin sqmJoin, TableGroup lhsTableGroup) {
|
||||||
|
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
||||||
|
|
||||||
|
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(
|
||||||
|
sqmJoin.getNavigablePath(),
|
||||||
|
sqmJoin.getExplicitAlias(),
|
||||||
|
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
||||||
|
determineLockMode( sqmJoin.getExplicitAlias() ),
|
||||||
|
sqlAliasBaseManager,
|
||||||
|
getSqlExpressionResolver(),
|
||||||
|
getCreationContext()
|
||||||
|
);
|
||||||
|
fromClauseIndex.register( sqmJoin, tableGroup );
|
||||||
|
|
||||||
|
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||||
|
sqmJoin.getNavigablePath(),
|
||||||
|
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
||||||
|
tableGroup,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
||||||
|
// add any additional join restrictions
|
||||||
|
if ( sqmJoin.getJoinPredicate() != null ) {
|
||||||
|
tableGroupJoin.applyPredicate(
|
||||||
|
(Predicate) sqmJoin.getJoinPredicate().accept( this )
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
consumeExplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
|
consumeImplicitJoins( sqmJoin, tableGroupJoin.getJoinedGroup() );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void consumeImplicitJoins(SqmPath<?> sqmPath, TableGroup tableGroup) {
|
||||||
log.tracef( "Visiting implicit joins for `%s`", sqmPath.getNavigablePath() );
|
log.tracef( "Visiting implicit joins for `%s`", sqmPath.getNavigablePath() );
|
||||||
|
|
||||||
sqmPath.visitImplicitJoinPaths(
|
sqmPath.visitImplicitJoinPaths(
|
||||||
joinedPath -> {
|
joinedPath -> {
|
||||||
log.tracef( "Starting implicit join handling for `%s`", joinedPath.getNavigablePath() );
|
log.tracef( "Starting implicit join handling for `%s`", joinedPath.getNavigablePath() );
|
||||||
|
|
||||||
|
// todo (6.0) : implement
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
// SqmPath handling
|
||||||
|
// - Note that SqmFrom references defined in the FROM-clause are already
|
||||||
|
// handled during `#visitFromClause`
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public TableGroup visitRootPath(SqmRoot<?> sqmRoot) {
|
||||||
|
final TableGroup resolved = fromClauseIndex.findTableGroup( sqmRoot.getNavigablePath() );
|
||||||
|
if ( resolved != null ) {
|
||||||
|
log.tracef( "SqmRoot [%s] resolved to existing TableGroup [%s]", sqmRoot, resolved );
|
||||||
|
return resolved;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InterpretationException( "SqmRoot not yet resolved to TableGroup" );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TableGroupJoin visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> sqmJoin) {
|
public TableGroupJoin visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> sqmJoin) {
|
||||||
final TableGroupJoin tableJoinJoin = fromClauseIndex.findTableGroupJoin( sqmJoin.getNavigablePath() );
|
// todo (6.0) : have this resolve to TableGroup instead?
|
||||||
if ( tableJoinJoin != null ) {
|
// - trying to remove tracking of TableGroupJoin in the x-refs
|
||||||
return tableJoinJoin;
|
|
||||||
|
final TableGroupJoin existing = fromClauseIndex.findTableGroupJoin( sqmJoin.getNavigablePath() );
|
||||||
|
if ( existing != null ) {
|
||||||
|
log.tracef( "SqmAttributeJoin [%s] resolved to existing TableGroup [%s]", sqmJoin, existing );
|
||||||
|
return existing;
|
||||||
}
|
}
|
||||||
|
|
||||||
final SqmPathSource<?> pathSource = sqmJoin.getReferencedPathSource();
|
throw new InterpretationException( "SqmAttributeJoin not yet resolved to TableGroup" );
|
||||||
|
|
||||||
final TableGroup lhsTableGroup = fromClauseIndex.findTableGroup( sqmJoin.getLhs().getNavigablePath() );
|
|
||||||
|
|
||||||
if ( pathSource.getSqmPathType() instanceof EmbeddableDomainType<?> ) {
|
|
||||||
// we need some special handling for embeddables...
|
|
||||||
|
|
||||||
// Above we checked for a TableGroupJoin associated with the `sqmJoin` path - but for
|
|
||||||
// an embeddable, check for its LHS too
|
|
||||||
final TableGroupJoin lhsTableGroupJoin = fromClauseIndex.findTableGroupJoin( sqmJoin.getNavigablePath() );
|
|
||||||
if ( lhsTableGroupJoin != null ) {
|
|
||||||
fromClauseIndex.register( sqmJoin, lhsTableGroupJoin );
|
|
||||||
return lhsTableGroupJoin;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next, although we don't want an actual TableGroup/TableGroupJoin created just for the
|
|
||||||
// embeddable, we do need to register a TableGroup against its NavigablePath.
|
|
||||||
// Specifically the TableGroup associated with the embeddable's LHS
|
|
||||||
fromClauseIndex.registerTableGroup( sqmJoin.getNavigablePath(), lhsTableGroup );
|
|
||||||
|
|
||||||
// we also still want to process its joins, adding them to the LHS TableGroup
|
|
||||||
sqmJoin.visitSqmJoins(
|
|
||||||
sqmJoinJoin -> {
|
|
||||||
final TableGroupJoin tableGroupJoin = (TableGroupJoin) sqmJoinJoin.accept( this );
|
|
||||||
if ( tableGroupJoin != null ) {
|
|
||||||
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
// return null - there is no TableGroupJoin that needs to be added
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final TableGroupJoin tableGroupJoin = ( (TableGroupJoinProducer) pathSource ).createTableGroupJoin(
|
|
||||||
sqmJoin.getNavigablePath(),
|
|
||||||
lhsTableGroup,
|
|
||||||
sqmJoin.getExplicitAlias(),
|
|
||||||
sqmJoin.getSqmJoinType().getCorrespondingSqlJoinType(),
|
|
||||||
LockMode.READ,
|
|
||||||
sqlAliasBaseManager,
|
|
||||||
creationContext
|
|
||||||
);
|
|
||||||
|
|
||||||
fromClauseIndex.register( sqmJoin, tableGroupJoin );
|
|
||||||
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
|
||||||
|
|
||||||
// add any additional join restrictions
|
|
||||||
if ( sqmJoin.getJoinPredicate() != null ) {
|
|
||||||
currentQuerySpec().applyPredicate(
|
|
||||||
(Predicate) sqmJoin.getJoinPredicate().accept( this )
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return tableGroupJoin;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private QuerySpec currentQuerySpec() {
|
private QuerySpec currentQuerySpec() {
|
||||||
|
@ -557,35 +619,30 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TableGroupJoin visitCrossJoin(SqmCrossJoin<?> sqmJoin) {
|
public TableGroupJoin visitCrossJoin(SqmCrossJoin<?> sqmJoin) {
|
||||||
final EntityPersister entityDescriptor = resolveEntityPersister( sqmJoin.getReferencedPathSource() );
|
// todo (6.0) : have this resolve to TableGroup instead?
|
||||||
|
// - trying to remove tracking of TableGroupJoin in the x-refs
|
||||||
|
|
||||||
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(
|
final TableGroupJoin existing = fromClauseIndex.findTableGroupJoin( sqmJoin.getNavigablePath() );
|
||||||
sqmJoin.getNavigablePath(),
|
if ( existing != null ) {
|
||||||
sqmJoin.getExplicitAlias(),
|
log.tracef( "SqmCrossJoin [%s] resolved to existing TableGroup [%s]", sqmJoin, existing );
|
||||||
JoinType.INNER,
|
return existing;
|
||||||
LockMode.NONE,
|
|
||||||
sqlAliasBaseManager,
|
|
||||||
getSqlExpressionResolver(),
|
|
||||||
getCreationContext()
|
|
||||||
);
|
|
||||||
|
|
||||||
fromClauseIndex.register( sqmJoin, tableGroup );
|
|
||||||
|
|
||||||
sqmJoin.visitSqmJoins(
|
|
||||||
sqmJoinJoin -> {
|
|
||||||
final TableGroupJoin tableGroupJoin = (TableGroupJoin) sqmJoinJoin.accept( this );
|
|
||||||
if ( tableGroupJoin != null ) {
|
|
||||||
tableGroup.addTableGroupJoin( tableGroupJoin );
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
return new TableGroupJoin( sqmJoin.getNavigablePath(), JoinType.CROSS, tableGroup, null );
|
throw new InterpretationException( "SqmCrossJoin not yet resolved to TableGroup" );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object visitQualifiedEntityJoin(SqmEntityJoin joinedFromElement) {
|
public TableGroupJoin visitQualifiedEntityJoin(SqmEntityJoin sqmJoin) {
|
||||||
throw new NotYetImplementedFor6Exception();
|
// todo (6.0) : have this resolve to TableGroup instead?
|
||||||
|
// - trying to remove tracking of TableGroupJoin in the x-refs
|
||||||
|
|
||||||
|
final TableGroupJoin existing = fromClauseIndex.findTableGroupJoin( sqmJoin.getNavigablePath() );
|
||||||
|
if ( existing != null ) {
|
||||||
|
log.tracef( "SqmEntityJoin [%s] resolved to existing TableGroup [%s]", sqmJoin, existing );
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InterpretationException( "SqmEntityJoin not yet resolved to TableGroup" );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -600,10 +657,6 @@ public abstract class BaseSqmToSqlAstConverter
|
||||||
@Override
|
@Override
|
||||||
public SqmPathInterpretation<?> visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath sqmPath) {
|
public SqmPathInterpretation<?> visitEmbeddableValuedPath(SqmEmbeddedValuedSimplePath sqmPath) {
|
||||||
return EmbeddableValuedPathInterpretation.from( sqmPath, this, this );
|
return EmbeddableValuedPathInterpretation.from( sqmPath, this, this );
|
||||||
// final SqmPath<?> lhs = sqmPath.getLhs();
|
|
||||||
// assert lhs != null;
|
|
||||||
//
|
|
||||||
// return (SqmPathInterpretation) sqmPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -274,6 +274,7 @@ public class SqmSelectToSqlAstConverter
|
||||||
JoinType.LEFT,
|
JoinType.LEFT,
|
||||||
LockMode.NONE,
|
LockMode.NONE,
|
||||||
getSqlAliasBaseManager(),
|
getSqlAliasBaseManager(),
|
||||||
|
getSqlExpressionResolver(),
|
||||||
getCreationContext()
|
getCreationContext()
|
||||||
);
|
);
|
||||||
lhs.addTableGroupJoin( tableGroupJoin );
|
lhs.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
|
@ -8,18 +8,21 @@ package org.hibernate.query.sqm.tree.from;
|
||||||
|
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.query.PathException;
|
import org.hibernate.query.PathException;
|
||||||
|
import org.hibernate.query.criteria.JpaEntityJoin;
|
||||||
|
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||||
import org.hibernate.query.sqm.spi.SqmCreationHelper;
|
import org.hibernate.query.sqm.spi.SqmCreationHelper;
|
||||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||||
import org.hibernate.query.sqm.tree.domain.AbstractSqmJoin;
|
import org.hibernate.query.sqm.tree.domain.AbstractSqmJoin;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedEntityJoin;
|
import org.hibernate.query.sqm.tree.domain.SqmTreatedEntityJoin;
|
||||||
|
import org.hibernate.query.sqm.tree.expression.SqmExpression;
|
||||||
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
|
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class SqmEntityJoin<T> extends AbstractSqmJoin<T,T> implements SqmQualifiedJoin<T,T> {
|
public class SqmEntityJoin<T> extends AbstractSqmJoin<T,T> implements SqmQualifiedJoin<T,T>, JpaEntityJoin<T> {
|
||||||
private final SqmRoot sqmRoot;
|
private final SqmRoot sqmRoot;
|
||||||
private SqmPredicate joinPredicate;
|
private SqmPredicate joinPredicate;
|
||||||
|
|
||||||
|
@ -48,6 +51,19 @@ public class SqmEntityJoin<T> extends AbstractSqmJoin<T,T> implements SqmQualifi
|
||||||
return getRoot();
|
return getRoot();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public SqmPath resolveIndexedAccess(
|
||||||
|
SqmExpression selector,
|
||||||
|
boolean isTerminal,
|
||||||
|
SqmCreationState creationState) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityDomainType<T> getModel() {
|
||||||
|
return (EntityDomainType<T>) super.getModel();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SqmPath getLhs() {
|
public SqmPath getLhs() {
|
||||||
// An entity-join has no LHS
|
// An entity-join has no LHS
|
||||||
|
|
|
@ -12,10 +12,12 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.query.PathException;
|
import org.hibernate.query.PathException;
|
||||||
|
import org.hibernate.query.criteria.JpaEntityJoin;
|
||||||
import org.hibernate.query.criteria.JpaRoot;
|
import org.hibernate.query.criteria.JpaRoot;
|
||||||
import org.hibernate.query.sqm.NodeBuilder;
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||||
|
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||||
import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
|
import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||||
|
@ -83,6 +85,20 @@ public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E>, Doma
|
||||||
return getReferencedPathSource();
|
return getReferencedPathSource();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> JpaEntityJoin<X> join(Class<X> entityJavaType) {
|
||||||
|
return join( nodeBuilder().getDomainModel().entity( entityJavaType ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <X> JpaEntityJoin<X> join(EntityDomainType<X> entity) {
|
||||||
|
final SqmEntityJoin<X> join = new SqmEntityJoin<>( entity, null, SqmJoinType.CROSS, this );
|
||||||
|
//noinspection unchecked
|
||||||
|
addSqmJoin( (SqmEntityJoin) join );
|
||||||
|
return join;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityDomainType<E> getModel() {
|
public EntityDomainType<E> getModel() {
|
||||||
return getReferencedPathSource();
|
return getReferencedPathSource();
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.ast.tree.from;
|
||||||
|
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
import org.hibernate.sql.ast.JoinType;
|
import org.hibernate.sql.ast.JoinType;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
import org.hibernate.sql.ast.spi.SqlAstWalker;
|
||||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
|
@ -22,7 +23,8 @@ public class TableGroupJoin implements SqlAstNode, DomainResultProducer {
|
||||||
private final NavigablePath navigablePath;
|
private final NavigablePath navigablePath;
|
||||||
private final JoinType joinType;
|
private final JoinType joinType;
|
||||||
private final TableGroup joinedGroup;
|
private final TableGroup joinedGroup;
|
||||||
private final Predicate predicate;
|
|
||||||
|
private Predicate predicate;
|
||||||
|
|
||||||
public TableGroupJoin(
|
public TableGroupJoin(
|
||||||
NavigablePath navigablePath,
|
NavigablePath navigablePath,
|
||||||
|
@ -35,6 +37,13 @@ public class TableGroupJoin implements SqlAstNode, DomainResultProducer {
|
||||||
this.predicate = predicate;
|
this.predicate = predicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TableGroupJoin(
|
||||||
|
NavigablePath navigablePath,
|
||||||
|
JoinType joinType,
|
||||||
|
TableGroup joinedGroup) {
|
||||||
|
this( navigablePath, joinType, joinedGroup, null );
|
||||||
|
}
|
||||||
|
|
||||||
public JoinType getJoinType() {
|
public JoinType getJoinType() {
|
||||||
return joinType;
|
return joinType;
|
||||||
}
|
}
|
||||||
|
@ -47,6 +56,10 @@ public class TableGroupJoin implements SqlAstNode, DomainResultProducer {
|
||||||
return predicate;
|
return predicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void applyPredicate(Predicate predicate) {
|
||||||
|
this.predicate = SqlAstTreeHelper.combinePredicates( this.predicate, predicate );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(SqlAstWalker sqlTreeWalker) {
|
public void accept(SqlAstWalker sqlTreeWalker) {
|
||||||
sqlTreeWalker.visitTableGroupJoin( this );
|
sqlTreeWalker.visitTableGroupJoin( this );
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.sql.ast.tree.from;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.JoinType;
|
import org.hibernate.sql.ast.JoinType;
|
||||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
|
@ -26,5 +27,6 @@ public interface TableGroupJoinProducer extends TableGroupProducer {
|
||||||
JoinType joinType,
|
JoinType joinType,
|
||||||
LockMode lockMode,
|
LockMode lockMode,
|
||||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||||
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
SqlAstCreationContext creationContext);
|
SqlAstCreationContext creationContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,7 +16,12 @@ import javax.persistence.criteria.CriteriaQuery;
|
||||||
import javax.persistence.criteria.ParameterExpression;
|
import javax.persistence.criteria.ParameterExpression;
|
||||||
import javax.persistence.criteria.Root;
|
import javax.persistence.criteria.Root;
|
||||||
|
|
||||||
|
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||||
|
import org.hibernate.query.criteria.HibernateCriteriaBuilder;
|
||||||
|
import org.hibernate.query.criteria.JpaCriteriaQuery;
|
||||||
|
import org.hibernate.query.criteria.JpaRoot;
|
||||||
import org.hibernate.query.spi.QueryParameterImplementor;
|
import org.hibernate.query.spi.QueryParameterImplementor;
|
||||||
|
import org.hibernate.query.sqm.NodeBuilder;
|
||||||
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
import org.hibernate.query.sqm.tree.expression.SqmParameter;
|
||||||
import org.hibernate.sql.exec.spi.JdbcParameter;
|
import org.hibernate.sql.exec.spi.JdbcParameter;
|
||||||
|
|
||||||
|
@ -137,6 +142,22 @@ public class BasicCriteriaExecutionTests extends BaseNonConfigCoreFunctionalTest
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCriteriaEntityJoin() {
|
||||||
|
final HibernateCriteriaBuilder criteriaBuilder = sessionFactory().getCriteriaBuilder();
|
||||||
|
|
||||||
|
final JpaCriteriaQuery<Object> criteria = criteriaBuilder.createQuery();
|
||||||
|
|
||||||
|
final JpaRoot<BasicEntity> root = criteria.from( BasicEntity.class );
|
||||||
|
root.join( BasicEntity.class );
|
||||||
|
|
||||||
|
criteria.select( root );
|
||||||
|
|
||||||
|
inSession(
|
||||||
|
session -> session.createQuery( criteria ).list()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Entity(name = "BasicEntity")
|
@Entity(name = "BasicEntity")
|
||||||
public static class BasicEntity {
|
public static class BasicEntity {
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue