initial working support for root entity loading via HQL

This commit is contained in:
Steve Ebersole 2019-09-16 13:09:43 -05:00
parent 00267022eb
commit 5500985afa
25 changed files with 559 additions and 108 deletions

4
design/todo-6.0.adoc Normal file
View File

@ -0,0 +1,4 @@
== Todo tasks related to 6.0 development
* Currently filtering tests to limit tests run during builds from Gradle. This is done in `gradle/java-module.gradle` via a test.include filter
* Tests for hibernate-orm-modules are run but failures are ignored

View File

@ -7,11 +7,12 @@
package org.hibernate.metamodel.mapping; package org.hibernate.metamodel.mapping;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.sql.results.spi.Fetchable;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface BasicValuedModelPart extends BasicValuedMapping, ModelPart { public interface BasicValuedModelPart extends BasicValuedMapping, ModelPart, Fetchable {
/** /**
* The table expression (table name or subselect) that contains * The table expression (table name or subselect) that contains
* the {@linkplain #getMappedColumnExpression mapped column} * the {@linkplain #getMappedColumnExpression mapped column}

View File

@ -15,6 +15,7 @@ import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.Clause;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**

View File

@ -15,4 +15,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*/ */
public interface MappingType extends ModelPart { public interface MappingType extends ModelPart {
JavaTypeDescriptor getMappedJavaTypeDescriptor(); JavaTypeDescriptor getMappedJavaTypeDescriptor();
@Override
default JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedJavaTypeDescriptor();
}
} }

View File

@ -12,6 +12,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState; import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer; import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
* Describes a mapping of related to any part of the app's domain model - e.g. * Describes a mapping of related to any part of the app's domain model - e.g.
@ -25,6 +26,7 @@ import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ModelPart extends MappingModelExpressable { public interface ModelPart extends MappingModelExpressable {
JavaTypeDescriptor getJavaTypeDescriptor();
/** /**
* Create a DomainResult for a specific reference to this ModelPart. * Create a DomainResult for a specific reference to this ModelPart.

View File

@ -9,6 +9,7 @@ package org.hibernate.metamodel.mapping.internal;
import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType; import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -36,6 +37,11 @@ public abstract class AbstractAttributeMapping implements AttributeMapping {
return type; return type;
} }
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override @Override
public ManagedMappingType getDeclaringType() { public ManagedMappingType getDeclaringType() {
return declaringType; return declaringType;

View File

@ -8,7 +8,9 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy; import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
@ -23,9 +25,12 @@ import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.ScalarDomainResultImpl; import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
import org.hibernate.sql.results.internal.domain.basic.BasicResultImpl;
import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState; import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -89,8 +94,21 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
TableGroup tableGroup, TableGroup tableGroup,
String resultVariable, String resultVariable,
DomainResultCreationState creationState) { DomainResultCreationState creationState) {
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
//noinspection unchecked
return new BasicResultImpl(
sqlSelection.getValuesArrayPosition(),
resultVariable,
getMappedTypeDescriptor().getMappedJavaTypeDescriptor(),
valueConverter,
navigablePath
);
}
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver(); final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
final SqlSelection sqlSelection = expressionResolver.resolveSqlSelection( return expressionResolver.resolveSqlSelection(
expressionResolver.resolveSqlExpression( expressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( SqlExpressionResolver.createColumnReferenceKey(
getContainingTableExpression(), getContainingTableExpression(),
@ -106,15 +124,6 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
valueConverter == null ? getMappedTypeDescriptor().getMappedJavaTypeDescriptor() : valueConverter.getRelationalJavaDescriptor(), valueConverter == null ? getMappedTypeDescriptor().getMappedJavaTypeDescriptor() : valueConverter.getRelationalJavaDescriptor(),
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration() creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
); );
//noinspection unchecked
return new ScalarDomainResultImpl(
sqlSelection.getValuesArrayPosition(),
resultVariable,
getMappedTypeDescriptor().getMappedJavaTypeDescriptor(),
valueConverter,
navigablePath
);
} }
@Override @Override
@ -143,6 +152,30 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
); );
} }
@Override
public Fetch generateFetch(
FetchParent fetchParent,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
final TableGroup tableGroup = creationState.getSqlAstCreationState()
.getFromClauseAccess()
.findTableGroup( fetchParent.getNavigablePath() );
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
return new BasicFetch(
sqlSelection.getValuesArrayPosition(),
fetchParent,
this,
getAttributeMetadataAccess().resolveAttributeMetadata( null ).isNullable(),
getConverter(),
fetchTiming,
creationState
);
}
@Override @Override
public Object disassemble(Object value, SharedSessionContractImplementor session) { public Object disassemble(Object value, SharedSessionContractImplementor session) {
if ( valueConverter != null ) { if ( valueConverter != null ) {
@ -168,9 +201,4 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
TypeConfiguration typeConfiguration) { TypeConfiguration typeConfiguration) {
action.accept( getJdbcMapping() ); action.accept( getJdbcMapping() );
} }
@Override
public int getStateArrayPosition() {
return 0;
}
} }

View File

@ -25,11 +25,12 @@ import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference; import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.internal.ScalarDomainResultImpl; import org.hibernate.sql.results.internal.domain.basic.BasicResultImpl;
import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState; import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeType; import org.hibernate.type.CompositeType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -88,6 +89,11 @@ public class MappingModelCreationHelper {
valuesConsumer.consume( value, idType ); valuesConsumer.consume( value, idType );
} }
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override @Override
public <T> DomainResult<T> createDomainResult( public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath, NavigablePath navigablePath,
@ -113,7 +119,7 @@ public class MappingModelCreationHelper {
); );
//noinspection unchecked //noinspection unchecked
return new ScalarDomainResultImpl( return new BasicResultImpl(
sqlSelection.getValuesArrayPosition(), sqlSelection.getValuesArrayPosition(),
resultVariable, resultVariable,
entityPersister.getIdentifierMapping().getMappedTypeDescriptor().getMappedJavaTypeDescriptor() entityPersister.getIdentifierMapping().getMappedTypeDescriptor().getMappedJavaTypeDescriptor()
@ -177,6 +183,11 @@ public class MappingModelCreationHelper {
return ( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getMappedTypeDescriptor(); return ( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getMappedTypeDescriptor();
} }
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override @Override
public <T> DomainResult<T> createDomainResult( public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath, NavigablePath navigablePath,
@ -227,7 +238,12 @@ public class MappingModelCreationHelper {
@Override @Override
public MappingType getMappedTypeDescriptor() { public MappingType getMappedTypeDescriptor() {
return null; return entityPersister;
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
} }
@Override @Override

View File

@ -9,7 +9,6 @@ package org.hibernate.metamodel.model.domain;
import javax.persistence.metamodel.Attribute; import javax.persistence.metamodel.Attribute;
import org.hibernate.metamodel.AttributeClassification; import org.hibernate.metamodel.AttributeClassification;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
@ -17,7 +16,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface PersistentAttribute<D,J> extends Attribute<D,J>, ModelPart { public interface PersistentAttribute<D,J> extends Attribute<D,J> {
@Override @Override
ManagedDomainType<D> getDeclaringType(); ManagedDomainType<D> getDeclaringType();

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.model.domain;
import javax.persistence.metamodel.SingularAttribute; import javax.persistence.metamodel.SingularAttribute;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.sqm.SqmJoinable; import org.hibernate.query.sqm.SqmJoinable;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
@ -18,7 +17,7 @@ import org.hibernate.query.sqm.SqmPathSource;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SingularPersistentAttribute<D,J> public interface SingularPersistentAttribute<D,J>
extends SingularAttribute<D,J>, PersistentAttribute<D,J>, ModelPart, SqmPathSource<J>, SqmJoinable { extends SingularAttribute<D,J>, PersistentAttribute<D,J>, SqmPathSource<J>, SqmJoinable {
@Override @Override
SimpleDomainType<J> getType(); SimpleDomainType<J> getType();

View File

@ -33,7 +33,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,J>, Serializable { public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,J>, Serializable {
private final ManagedDomainType<D> declaringType; private final ManagedDomainType<D> declaringType;
private final String name; private final String name;
private final JavaTypeDescriptor<J> attributeType; private final JavaTypeDescriptor<J> attributeJtd;
private final AttributeClassification attributeClassification; private final AttributeClassification attributeClassification;
@ -44,14 +44,14 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
protected AbstractAttribute( protected AbstractAttribute(
ManagedDomainType<D> declaringType, ManagedDomainType<D> declaringType,
String name, String name,
JavaTypeDescriptor<J> attributeType, JavaTypeDescriptor<J> attributeJtd,
AttributeClassification attributeClassification, AttributeClassification attributeClassification,
SimpleDomainType<B> valueType, SimpleDomainType<B> valueType,
Member member, Member member,
MetadataContext metadataContext) { MetadataContext metadataContext) {
this.declaringType = declaringType; this.declaringType = declaringType;
this.name = name; this.name = name;
this.attributeType = attributeType; this.attributeJtd = attributeJtd;
this.attributeClassification = attributeClassification; this.attributeClassification = attributeClassification;
this.valueType = valueType; this.valueType = valueType;
this.member = member; this.member = member;
@ -64,7 +64,7 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
@Override @Override
public Class<J> getJavaType() { public Class<J> getJavaType() {
return attributeType.getJavaType(); return attributeJtd.getJavaType();
} }
public SimpleDomainType<B> getSqmPathType() { public SimpleDomainType<B> getSqmPathType() {
@ -73,7 +73,7 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
@Override @Override
public JavaTypeDescriptor<J> getAttributeJavaTypeDescriptor() { public JavaTypeDescriptor<J> getAttributeJavaTypeDescriptor() {
return attributeType; return attributeJtd;
} }
@Override @Override

View File

@ -6413,9 +6413,10 @@ public abstract class AbstractEntityPersister
EntityMappingType treatTargetType) { EntityMappingType treatTargetType) {
visitStateArrayContributors( visitStateArrayContributors(
mapping -> { mapping -> {
if ( mapping.isDeclaredOnTypeOrSuperType( treatTargetType ) ) { // treat limits are already handled in `#visitAttributeMappings` (called from `#visitStateArrayContributors`)
// if ( mapping.isDeclaredOnTypeOrSuperType( treatTargetType ) ) {
fetchableConsumer.accept( mapping ); fetchableConsumer.accept( mapping );
} // }
}, },
treatTargetType treatTargetType
); );
@ -6443,7 +6444,7 @@ public abstract class AbstractEntityPersister
declaredAttributeMappings.values().forEach( action ); declaredAttributeMappings.values().forEach( action );
if ( targetType == null ) { if ( targetType == null || targetType.isTypeOrSuperType( this ) ) {
visitSubTypeAttributeMappings( action ); visitSubTypeAttributeMappings( action );
} }
} }

View File

@ -21,6 +21,7 @@ import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.sql.exec.spi.JdbcParameterBinding; import org.hibernate.sql.exec.spi.JdbcParameterBinding;
import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**

View File

@ -9,6 +9,7 @@ package org.hibernate.sql.results.internal.domain;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultCreationState; import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch; import org.hibernate.sql.results.spi.Fetch;
@ -33,6 +34,11 @@ public abstract class AbstractFetchParent implements FetchParent {
this.fetches = creationState.visitFetches( this ); this.fetches = creationState.visitFetches( this );
} }
@Override
public ManagedMappingType getReferencedMappingType() {
return (ManagedMappingType) fetchContainer;
}
@Override @Override
public NavigablePath getNavigablePath() { public NavigablePath getNavigablePath() {
return navigablePath; return navigablePath;

View File

@ -0,0 +1,110 @@
/*
* 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.sql.results.internal.domain;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.BiDirectionalFetch;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* Implementation of BiDirectionalFetch for the `oa` case - the bi-dir fetch
* refers to another fetch (`a`)
*
* @author Steve Ebersole
*/
public class BiDirectionalFetchImpl implements BiDirectionalFetch {
private final NavigablePath navigablePath;
private final FetchParent fetchParent;
private final Fetch referencedFetch;
/**
* Create the bi-dir fetch
*
* @param navigablePath `Person(p).address.owner.address`
* @param fetchParent The parent for the `oa` fetch is `o`
* @param referencedFetch `RootBiDirectionalFetchImpl(a)` (because `a` is itself also a bi-dir fetch referring to the `p root)
*/
public BiDirectionalFetchImpl(
NavigablePath navigablePath,
FetchParent fetchParent,
Fetch referencedFetch) {
this.navigablePath = navigablePath;
this.fetchParent = fetchParent;
this.referencedFetch = referencedFetch;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public NavigablePath getReferencedPath() {
return referencedFetch.getNavigablePath();
}
@Override
public FetchParent getFetchParent() {
return fetchParent;
}
@Override
public Fetchable getFetchedMapping() {
return referencedFetch.getFetchedMapping();
}
@Override
public boolean isNullable() {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public DomainResultAssembler createAssembler(
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
return new CircularFetchAssembler(
getReferencedPath(),
referencedFetch.getFetchedMapping().getJavaTypeDescriptor()
);
}
private static class CircularFetchAssembler implements DomainResultAssembler {
private final NavigablePath circularPath;
private final JavaTypeDescriptor javaTypeDescriptor;
public CircularFetchAssembler(
NavigablePath circularPath,
JavaTypeDescriptor javaTypeDescriptor) {
this.circularPath = circularPath;
this.javaTypeDescriptor = javaTypeDescriptor;
}
@Override
public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
return rowProcessingState.resolveInitializer( circularPath ).getInitializedInstance();
}
@Override
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
return javaTypeDescriptor;
}
}
}

View File

@ -0,0 +1,138 @@
/*
* 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.sql.results.internal.domain;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.BiDirectionalFetch;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.EntityResult;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.sql.results.spi.Initializer;
import org.hibernate.sql.results.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Andrea Boriero
*/
public class RootBiDirectionalFetchImpl implements BiDirectionalFetch, Fetchable {
private final NavigablePath navigablePath;
private final FetchParent fetchParent;
private final EntityResult referencedRoot;
public RootBiDirectionalFetchImpl(
NavigablePath navigablePath,
FetchParent fetchParent,
EntityResult referencedRoot) {
this.fetchParent = fetchParent;
this.referencedRoot = referencedRoot;
this.navigablePath = navigablePath;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public NavigablePath getReferencedPath() {
return referencedRoot.getNavigablePath();
}
@Override
public FetchParent getFetchParent() {
return fetchParent;
}
@Override
public Fetchable getFetchedMapping() {
return null;
}
@Override
public boolean isNullable() {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public DomainResultAssembler createAssembler(
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
return new CircularFetchAssembler(
getReferencedPath(),
referencedRoot.getResultJavaTypeDescriptor()
);
}
@Override
public String getFetchableName() {
// An entity itself is not fetchable
return null;
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return referencedRoot.getResultJavaTypeDescriptor();
}
@Override
public FetchStrategy getMappedFetchStrategy() {
throw new UnsupportedOperationException();
}
@Override
public Fetch generateFetch(
FetchParent fetchParent,
FetchTiming fetchTiming,
boolean selected,
LockMode lockMode,
String resultVariable,
DomainResultCreationState creationState) {
throw new UnsupportedOperationException();
}
private static class CircularFetchAssembler implements DomainResultAssembler {
private final NavigablePath circularPath;
private final JavaTypeDescriptor javaTypeDescriptor;
public CircularFetchAssembler(
NavigablePath circularPath,
JavaTypeDescriptor javaTypeDescriptor) {
this.circularPath = circularPath;
this.javaTypeDescriptor = javaTypeDescriptor;
}
@Override
public Object assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
Initializer initializer = rowProcessingState.resolveInitializer( circularPath );
if ( initializer.getInitializedInstance() == null ) {
initializer.resolveKey( rowProcessingState );
initializer.resolveInstance( rowProcessingState );
initializer.initializeInstance( rowProcessingState );
}
return initializer.getInitializedInstance();
}
@Override
public JavaTypeDescriptor getAssembledJavaTypeDescriptor() {
return javaTypeDescriptor;
}
}
}

View File

@ -0,0 +1,89 @@
/*
* 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.sql.results.internal.domain.basic;
import java.util.function.Consumer;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.sql.results.spi.FetchParentAccess;
import org.hibernate.sql.results.spi.Fetchable;
import org.hibernate.sql.results.spi.Initializer;
/**
* @author Steve Ebersole
*/
public class BasicFetch implements Fetch {
private final NavigablePath navigablePath;
private final FetchParent fetchParent;
private final BasicValuedModelPart valuedMapping;
private final boolean nullable;
private final BasicResultAssembler assembler;
private final FetchTiming fetchTiming;
public BasicFetch(
int valuesArrayPosition,
FetchParent fetchParent,
BasicValuedModelPart valuedMapping,
boolean nullable,
BasicValueConverter valueConverter,
FetchTiming fetchTiming,
DomainResultCreationState creationState) {
this.nullable = nullable;
this.navigablePath = fetchParent.getNavigablePath().append( valuedMapping.getFetchableName() );
this.fetchParent = fetchParent;
this.valuedMapping = valuedMapping;
this.fetchTiming = fetchTiming;
//noinspection unchecked
this.assembler = new BasicResultAssembler(
valuesArrayPosition,
valuedMapping.getJavaTypeDescriptor(),
valueConverter
);
}
@Override
public FetchParent getFetchParent() {
return fetchParent;
}
@Override
public Fetchable getFetchedMapping() {
return valuedMapping;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public boolean isNullable() {
return nullable;
}
@Override
public DomainResultAssembler createAssembler(
FetchParentAccess parentAccess,
Consumer<Initializer> collector,
AssemblerCreationState creationState) {
return assembler;
}
}

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/ */
package org.hibernate.sql.results.internal; package org.hibernate.sql.results.internal.domain.basic;
import org.hibernate.Internal; import org.hibernate.Internal;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;

View File

@ -4,7 +4,7 @@
* License: GNU Lesser General Public License (LGPL), version 2.1 or later * 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 * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/ */
package org.hibernate.sql.results.internal; package org.hibernate.sql.results.internal.domain.basic;
import java.util.function.Consumer; import java.util.function.Consumer;
@ -20,7 +20,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> { public class BasicResultImpl<T> implements ScalarDomainResult<T> {
private final String resultVariable; private final String resultVariable;
private final JavaTypeDescriptor<T> javaTypeDescriptor; private final JavaTypeDescriptor<T> javaTypeDescriptor;
@ -28,14 +28,14 @@ public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
private final DomainResultAssembler<T> assembler; private final DomainResultAssembler<T> assembler;
public ScalarDomainResultImpl( public BasicResultImpl(
int jdbcValuesArrayPosition, int jdbcValuesArrayPosition,
String resultVariable, String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor) { JavaTypeDescriptor<T> javaTypeDescriptor) {
this( jdbcValuesArrayPosition, resultVariable, javaTypeDescriptor, (NavigablePath) null ); this( jdbcValuesArrayPosition, resultVariable, javaTypeDescriptor, (NavigablePath) null );
} }
public ScalarDomainResultImpl( public BasicResultImpl(
int jdbcValuesArrayPosition, int jdbcValuesArrayPosition,
String resultVariable, String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor, JavaTypeDescriptor<T> javaTypeDescriptor,
@ -48,7 +48,7 @@ public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
this.assembler = new BasicResultAssembler<>( jdbcValuesArrayPosition, javaTypeDescriptor ); this.assembler = new BasicResultAssembler<>( jdbcValuesArrayPosition, javaTypeDescriptor );
} }
public ScalarDomainResultImpl( public BasicResultImpl(
int valuesArrayPosition, int valuesArrayPosition,
String resultVariable, String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor, JavaTypeDescriptor<T> javaTypeDescriptor,
@ -56,7 +56,7 @@ public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
this( valuesArrayPosition, resultVariable, javaTypeDescriptor, valueConverter, null ); this( valuesArrayPosition, resultVariable, javaTypeDescriptor, valueConverter, null );
} }
public ScalarDomainResultImpl( public BasicResultImpl(
int valuesArrayPosition, int valuesArrayPosition,
String resultVariable, String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor, JavaTypeDescriptor<T> javaTypeDescriptor,

View File

@ -92,16 +92,16 @@ public abstract class AbstractEntityMappingNode extends AbstractFetchParent impl
); );
} }
entityDescriptor.visitAttributeMappings( // entityDescriptor.visitAttributeMappings(
mapping -> attributeDomainResults.add( // mapping -> attributeDomainResults.add(
mapping.createDomainResult( // mapping.createDomainResult(
navigablePath.append( mapping.getAttributeName() ), // navigablePath.append( mapping.getAttributeName() ),
entityTableGroup, // entityTableGroup,
null, // null,
creationState // creationState
) // )
) // )
); // );
// todo (6.0) : handle other special navigables such as discriminator, row-id, tenant-id, etc // todo (6.0) : handle other special navigables such as discriminator, row-id, tenant-id, etc
} }

View File

@ -0,0 +1,58 @@
/*
* 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.sql.results.spi;
import org.hibernate.query.NavigablePath;
/**
* @asciidoc
*
* Marker interface for Fetches that are actually references to
* another fetch based on "normalized navigable path"
*
* The following query is used throughout the javadocs for these impls
* to help describe what it going on and why certain methods do certain things.
*
* ````
* @Entity
* class Person {
* ...
* @ManyToOne(mappedBy="owner")
* Address getAddress() {...}
* }
*
* @Entity
* class Address {
* ...
* @ManyToOne
* Person getOwner() {...}
* }
*
* from Person p
* join fetch p.address a
* join fetch a.owner o
* join fetch o.address oa
* ````
*
* Here we have one root result and 3 fetches. 2 of the fetches are bi-directional:
*
* `o`:: The paths `p` and `p.address.owner` (aliased as `o`) are the same table reference in SQL terms
* `oa`:: The paths `p.address` and `p.address.owner.address` (aliased as `oa`) are again the same table reference
*
* @author Steve Ebersole
*/
public interface BiDirectionalFetch extends Fetch {
/**
* The NavigablePath for the DomainResult or Fetch that this Fetch refers to.
*
* For `o`, the referenced path is `p`. For `oa`, it's `p.address`
*
* Different from {@link #getNavigablePath()} which returns this fetch's path, i.e.
* `p.address.owner` and `p.address.owner.address` respectively
*/
NavigablePath getReferencedPath();
}

View File

@ -7,8 +7,9 @@
package org.hibernate.sql.results.spi; package org.hibernate.sql.results.spi;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.internal.domain.BiDirectionalFetchImpl;
import org.hibernate.sql.results.internal.domain.RootBiDirectionalFetchImpl;
/** /**
* Maintains state while processing a Fetch graph to be able to detect * Maintains state while processing a Fetch graph to be able to detect
@ -19,57 +20,36 @@ import org.hibernate.query.NavigablePath;
public class CircularFetchDetector { public class CircularFetchDetector {
public Fetch findBiDirectionalFetch(FetchParent fetchParent, Fetchable fetchable) { public Fetch findBiDirectionalFetch(FetchParent fetchParent, Fetchable fetchable) {
// bi-directional references are a special case that need special treatment. if ( ! fetchable.isCircular( fetchParent ) ) {
// return null;
// `p.address.resident.homeAddress }
//
// what we mean is a fetch path like `a.parent.child.parent`. here the terminal assert fetchParent instanceof Fetch;
// `parent` name is the same reference as its parent's (`a.parent.child`) final Fetch fetchParentAsFetch = (Fetch) fetchParent;
// parent's (a.parent`) path.
//
// In such a case we want to (mostly) reuse the "parent parent" path fetch
//
// see if we have such a case...
final NavigablePath parentParentPath = fetchParent.getNavigablePath().getParent(); final NavigablePath parentParentPath = fetchParent.getNavigablePath().getParent();
if ( parentParentPath != null ) { assert fetchParent.getNavigablePath().getParent() != null;
if ( fetchable.isCircular( fetchParent ) ) {
if ( fetchParent instanceof Fetch ) {
final FetchParent parentFetchParent = ( (Fetch) fetchParent ).getFetchParent();
// we do... assert fetchParentAsFetch.getFetchParent().getNavigablePath().equals( parentParentPath );
//
// in other words, the `Fetchable`'s `NavigablePath`, relative to its FetchParent here would
// be:
// a.parent.child.parent
//
// it's parentPath is `a.parent.child` so its parentParentPath is `a.parent`. so this Fetchable's
// path is really the same reference as its parentParentPath. This is a special case, handled here...
// first, this *should* mean we have already "seen" the Fetch generated parentParentPath. So if ( fetchParentAsFetch.getFetchParent() instanceof Fetch ) {
// look up in the `navigablePathFetchMap` to get that Fetch return new BiDirectionalFetchImpl(
fetchParent.getNavigablePath().append( fetchable.getFetchableName() ),
// and use it to create and register the "bi directional" form fetchParent,
fetchParentAsFetch
final NavigablePath fetchableNavigablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() ); );
// return new BiDirectionalFetchImpl(
// parentFetchParent,
// fetchableNavigablePath
// );
} }
else { else {
// return new RootBiDirectionalFetchImpl( assert fetchParentAsFetch instanceof EntityResult;
// new NavigablePath( fetchable.getJavaTypeDescriptor().getJavaType().getName() ),
// fetchable.getJavaTypeDescriptor(),
// new NavigablePath( fetchable.getNavigableName() )
// );
}
}
}
// return null; // note : the "`fetchParentAsFetch` is `RootBiDirectionalFetchImpl`" case would
// be handled in the `Fetch` block since `RootBiDirectionalFetchImpl` is a Fetch
throw new NotYetImplementedFor6Exception( getClass() ); return new RootBiDirectionalFetchImpl(
fetchParent.getNavigablePath().append( fetchable.getFetchableName() ),
fetchParent,
(EntityResult) fetchParentAsFetch
);
}
} }
} }

View File

@ -8,6 +8,7 @@ package org.hibernate.sql.results.spi;
import java.util.List; import java.util.List;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
/** /**
@ -18,6 +19,11 @@ import org.hibernate.query.NavigablePath;
public interface FetchParent { public interface FetchParent {
FetchableContainer getReferencedMappingContainer(); FetchableContainer getReferencedMappingContainer();
/**
* This parent's type
*/
ManagedMappingType getReferencedMappingType();
/** /**
* Get the property path to this parent * Get the property path to this parent
*/ */

View File

@ -37,6 +37,11 @@ public interface BasicType<T> extends Type, BasicDomainType<T>, MappingType, Bas
return this; return this;
} }
@Override
default JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedJavaTypeDescriptor();
}
@Override @Override
default JdbcMapping getJdbcMapping() { default JdbcMapping getJdbcMapping() {
return this; return this;

View File

@ -12,7 +12,6 @@ import org.hibernate.cfg.AvailableSettings;
import org.hibernate.metamodel.mapping.MappingModelExpressable; import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter; import org.hibernate.metamodel.model.convert.internal.OrdinalEnumValueConverter;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.convert.spi.EnumValueConverter;
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender; import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender;
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity; import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
@ -31,15 +30,12 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.select.SelectClause; import org.hibernate.sql.ast.tree.select.SelectClause;
import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.spi.JdbcSelect; import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.internal.BasicResultAssembler; import org.hibernate.sql.results.internal.domain.basic.BasicResultAssembler;
import org.hibernate.sql.results.internal.ScalarDomainResultImpl; import org.hibernate.sql.results.internal.domain.basic.BasicResultImpl;
import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.spi.DomainResult; import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler; import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.type.CustomType;
import org.hibernate.type.EnumType;
import org.hibernate.type.internal.StandardBasicTypeImpl; import org.hibernate.type.internal.StandardBasicTypeImpl;
import org.hibernate.usertype.UserType;
import org.hibernate.testing.hamcrest.AssignableMatcher; import org.hibernate.testing.hamcrest.AssignableMatcher;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
@ -196,8 +192,8 @@ public class SmokeTests {
assertThat( sqlAst.getDomainResultDescriptors().size(), is( 1 ) ); assertThat( sqlAst.getDomainResultDescriptors().size(), is( 1 ) );
final DomainResult domainResult = sqlAst.getDomainResultDescriptors().get( 0 ); final DomainResult domainResult = sqlAst.getDomainResultDescriptors().get( 0 );
assertThat( domainResult, instanceOf( ScalarDomainResultImpl.class ) ); assertThat( domainResult, instanceOf( BasicResultImpl.class ) );
final ScalarDomainResultImpl scalarDomainResult = (ScalarDomainResultImpl) domainResult; final BasicResultImpl scalarDomainResult = (BasicResultImpl) domainResult;
assertThat( scalarDomainResult.getAssembler(), instanceOf( BasicResultAssembler.class ) ); assertThat( scalarDomainResult.getAssembler(), instanceOf( BasicResultAssembler.class ) );
final BasicResultAssembler<?> assembler = (BasicResultAssembler) scalarDomainResult.getAssembler(); final BasicResultAssembler<?> assembler = (BasicResultAssembler) scalarDomainResult.getAssembler();
assertThat( assembler.getValueConverter(), notNullValue() ); assertThat( assembler.getValueConverter(), notNullValue() );
@ -207,7 +203,7 @@ public class SmokeTests {
"e" "e"
).append( "gender" ); ).append( "gender" );
assertThat( domainResult.getNavigablePath(), equalTo( expectedSelectedPath ) ); assertThat( domainResult.getNavigablePath(), equalTo( expectedSelectedPath ) );
assertThat( domainResult, instanceOf( ScalarDomainResultImpl.class ) ); assertThat( domainResult, instanceOf( BasicResultImpl.class ) );
// ScalarDomainResultImpl creates and caches the assembler at its creation. // ScalarDomainResultImpl creates and caches the assembler at its creation.
// this just gets access to that cached one // this just gets access to that cached one