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;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.sql.results.spi.Fetchable;
/**
* @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 {@linkplain #getMappedColumnExpression mapped column}

View File

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

View File

@ -15,4 +15,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*/
public interface MappingType extends ModelPart {
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.DomainResultCreationState;
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.
@ -25,6 +26,7 @@ import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
* @author Steve Ebersole
*/
public interface ModelPart extends MappingModelExpressable {
JavaTypeDescriptor getJavaTypeDescriptor();
/**
* 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.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
@ -36,6 +37,11 @@ public abstract class AbstractAttributeMapping implements AttributeMapping {
return type;
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override
public ManagedMappingType getDeclaringType() {
return declaringType;

View File

@ -8,7 +8,9 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchStrategy;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
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.tree.expression.ColumnReference;
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.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
import org.hibernate.sql.results.spi.FetchParent;
import org.hibernate.type.BasicType;
import org.hibernate.type.spi.TypeConfiguration;
@ -89,8 +94,21 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
TableGroup tableGroup,
String resultVariable,
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 SqlSelection sqlSelection = expressionResolver.resolveSqlSelection(
return expressionResolver.resolveSqlSelection(
expressionResolver.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
getContainingTableExpression(),
@ -106,15 +124,6 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
valueConverter == null ? getMappedTypeDescriptor().getMappedJavaTypeDescriptor() : valueConverter.getRelationalJavaDescriptor(),
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
);
//noinspection unchecked
return new ScalarDomainResultImpl(
sqlSelection.getValuesArrayPosition(),
resultVariable,
getMappedTypeDescriptor().getMappedJavaTypeDescriptor(),
valueConverter,
navigablePath
);
}
@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
public Object disassemble(Object value, SharedSessionContractImplementor session) {
if ( valueConverter != null ) {
@ -168,9 +201,4 @@ public class BasicValuedSingularAttributeMapping extends AbstractSingularAttribu
TypeConfiguration typeConfiguration) {
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.Expression;
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.DomainResultCreationState;
import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
@ -88,6 +89,11 @@ public class MappingModelCreationHelper {
valuesConsumer.consume( value, idType );
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
@ -113,7 +119,7 @@ public class MappingModelCreationHelper {
);
//noinspection unchecked
return new ScalarDomainResultImpl(
return new BasicResultImpl(
sqlSelection.getValuesArrayPosition(),
resultVariable,
entityPersister.getIdentifierMapping().getMappedTypeDescriptor().getMappedJavaTypeDescriptor()
@ -177,6 +183,11 @@ public class MappingModelCreationHelper {
return ( (BasicValuedModelPart) entityPersister.getIdentifierType() ).getMappedTypeDescriptor();
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
@ -227,7 +238,12 @@ public class MappingModelCreationHelper {
@Override
public MappingType getMappedTypeDescriptor() {
return null;
return entityPersister;
}
@Override
public JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedTypeDescriptor().getMappedJavaTypeDescriptor();
}
@Override

View File

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

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.model.domain;
import javax.persistence.metamodel.SingularAttribute;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.sqm.SqmJoinable;
import org.hibernate.query.sqm.SqmPathSource;
@ -18,7 +17,7 @@ import org.hibernate.query.sqm.SqmPathSource;
* @author Steve Ebersole
*/
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
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 {
private final ManagedDomainType<D> declaringType;
private final String name;
private final JavaTypeDescriptor<J> attributeType;
private final JavaTypeDescriptor<J> attributeJtd;
private final AttributeClassification attributeClassification;
@ -44,14 +44,14 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
protected AbstractAttribute(
ManagedDomainType<D> declaringType,
String name,
JavaTypeDescriptor<J> attributeType,
JavaTypeDescriptor<J> attributeJtd,
AttributeClassification attributeClassification,
SimpleDomainType<B> valueType,
Member member,
MetadataContext metadataContext) {
this.declaringType = declaringType;
this.name = name;
this.attributeType = attributeType;
this.attributeJtd = attributeJtd;
this.attributeClassification = attributeClassification;
this.valueType = valueType;
this.member = member;
@ -64,7 +64,7 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
@Override
public Class<J> getJavaType() {
return attributeType.getJavaType();
return attributeJtd.getJavaType();
}
public SimpleDomainType<B> getSqmPathType() {
@ -73,7 +73,7 @@ public abstract class AbstractAttribute<D,J,B> implements PersistentAttribute<D,
@Override
public JavaTypeDescriptor<J> getAttributeJavaTypeDescriptor() {
return attributeType;
return attributeJtd;
}
@Override

View File

@ -6413,9 +6413,10 @@ public abstract class AbstractEntityPersister
EntityMappingType treatTargetType) {
visitStateArrayContributors(
mapping -> {
if ( mapping.isDeclaredOnTypeOrSuperType( treatTargetType ) ) {
// treat limits are already handled in `#visitAttributeMappings` (called from `#visitStateArrayContributors`)
// if ( mapping.isDeclaredOnTypeOrSuperType( treatTargetType ) ) {
fetchableConsumer.accept( mapping );
}
// }
},
treatTargetType
);
@ -6443,7 +6444,7 @@ public abstract class AbstractEntityPersister
declaredAttributeMappings.values().forEach( action );
if ( targetType == null ) {
if ( targetType == null || targetType.isTypeOrSuperType( this ) ) {
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.JdbcParameterBindings;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
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.List;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.sql.results.spi.Fetch;
@ -33,6 +34,11 @@ public abstract class AbstractFetchParent implements FetchParent {
this.fetches = creationState.visitFetches( this );
}
@Override
public ManagedMappingType getReferencedMappingType() {
return (ManagedMappingType) fetchContainer;
}
@Override
public NavigablePath getNavigablePath() {
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
* 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.metamodel.model.convert.spi.BasicValueConverter;

View File

@ -4,7 +4,7 @@
* 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;
package org.hibernate.sql.results.internal.domain.basic;
import java.util.function.Consumer;
@ -20,7 +20,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
public class BasicResultImpl<T> implements ScalarDomainResult<T> {
private final String resultVariable;
private final JavaTypeDescriptor<T> javaTypeDescriptor;
@ -28,14 +28,14 @@ public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
private final DomainResultAssembler<T> assembler;
public ScalarDomainResultImpl(
public BasicResultImpl(
int jdbcValuesArrayPosition,
String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor) {
this( jdbcValuesArrayPosition, resultVariable, javaTypeDescriptor, (NavigablePath) null );
}
public ScalarDomainResultImpl(
public BasicResultImpl(
int jdbcValuesArrayPosition,
String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor,
@ -48,7 +48,7 @@ public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
this.assembler = new BasicResultAssembler<>( jdbcValuesArrayPosition, javaTypeDescriptor );
}
public ScalarDomainResultImpl(
public BasicResultImpl(
int valuesArrayPosition,
String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor,
@ -56,7 +56,7 @@ public class ScalarDomainResultImpl<T> implements ScalarDomainResult<T> {
this( valuesArrayPosition, resultVariable, javaTypeDescriptor, valueConverter, null );
}
public ScalarDomainResultImpl(
public BasicResultImpl(
int valuesArrayPosition,
String resultVariable,
JavaTypeDescriptor<T> javaTypeDescriptor,

View File

@ -92,16 +92,16 @@ public abstract class AbstractEntityMappingNode extends AbstractFetchParent impl
);
}
entityDescriptor.visitAttributeMappings(
mapping -> attributeDomainResults.add(
mapping.createDomainResult(
navigablePath.append( mapping.getAttributeName() ),
entityTableGroup,
null,
creationState
)
)
);
// entityDescriptor.visitAttributeMappings(
// mapping -> attributeDomainResults.add(
// mapping.createDomainResult(
// navigablePath.append( mapping.getAttributeName() ),
// entityTableGroup,
// null,
// creationState
// )
// )
// );
// 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;
import org.hibernate.NotYetImplementedFor6Exception;
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
@ -19,57 +20,36 @@ import org.hibernate.query.NavigablePath;
public class CircularFetchDetector {
public Fetch findBiDirectionalFetch(FetchParent fetchParent, Fetchable fetchable) {
// bi-directional references are a special case that need special treatment.
//
// `p.address.resident.homeAddress
//
// what we mean is a fetch path like `a.parent.child.parent`. here the terminal
// `parent` name is the same reference as its parent's (`a.parent.child`)
// 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();
if ( parentParentPath != null ) {
if ( fetchable.isCircular( fetchParent ) ) {
if ( fetchParent instanceof Fetch ) {
final FetchParent parentFetchParent = ( (Fetch) fetchParent ).getFetchParent();
// we do...
//
// 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
// look up in the `navigablePathFetchMap` to get that Fetch
// and use it to create and register the "bi directional" form
final NavigablePath fetchableNavigablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() );
// return new BiDirectionalFetchImpl(
// parentFetchParent,
// fetchableNavigablePath
// );
}
else {
// return new RootBiDirectionalFetchImpl(
// new NavigablePath( fetchable.getJavaTypeDescriptor().getJavaType().getName() ),
// fetchable.getJavaTypeDescriptor(),
// new NavigablePath( fetchable.getNavigableName() )
// );
}
}
if ( ! fetchable.isCircular( fetchParent ) ) {
return null;
}
// return null;
assert fetchParent instanceof Fetch;
final Fetch fetchParentAsFetch = (Fetch) fetchParent;
throw new NotYetImplementedFor6Exception( getClass() );
final NavigablePath parentParentPath = fetchParent.getNavigablePath().getParent();
assert fetchParent.getNavigablePath().getParent() != null;
assert fetchParentAsFetch.getFetchParent().getNavigablePath().equals( parentParentPath );
if ( fetchParentAsFetch.getFetchParent() instanceof Fetch ) {
return new BiDirectionalFetchImpl(
fetchParent.getNavigablePath().append( fetchable.getFetchableName() ),
fetchParent,
fetchParentAsFetch
);
}
else {
assert fetchParentAsFetch instanceof EntityResult;
// note : the "`fetchParentAsFetch` is `RootBiDirectionalFetchImpl`" case would
// be handled in the `Fetch` block since `RootBiDirectionalFetchImpl` is a Fetch
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 org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath;
/**
@ -18,6 +19,11 @@ import org.hibernate.query.NavigablePath;
public interface FetchParent {
FetchableContainer getReferencedMappingContainer();
/**
* This parent's type
*/
ManagedMappingType getReferencedMappingType();
/**
* 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;
}
@Override
default JavaTypeDescriptor getJavaTypeDescriptor() {
return getMappedJavaTypeDescriptor();
}
@Override
default JdbcMapping getJdbcMapping() {
return this;

View File

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