initial working support for root entity loading via HQL
This commit is contained in:
parent
00267022eb
commit
5500985afa
|
@ -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
|
|
@ -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}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,4 +15,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
*/
|
||||
public interface MappingType extends ModelPart {
|
||||
JavaTypeDescriptor getMappedJavaTypeDescriptor();
|
||||
|
||||
@Override
|
||||
default JavaTypeDescriptor getJavaTypeDescriptor() {
|
||||
return getMappedJavaTypeDescriptor();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
|
@ -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,
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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...
|
||||
if ( ! fetchable.isCircular( fetchParent ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
assert fetchParent instanceof Fetch;
|
||||
final Fetch fetchParentAsFetch = (Fetch) fetchParent;
|
||||
|
||||
final NavigablePath parentParentPath = fetchParent.getNavigablePath().getParent();
|
||||
if ( parentParentPath != null ) {
|
||||
if ( fetchable.isCircular( fetchParent ) ) {
|
||||
if ( fetchParent instanceof Fetch ) {
|
||||
final FetchParent parentFetchParent = ( (Fetch) fetchParent ).getFetchParent();
|
||||
assert fetchParent.getNavigablePath().getParent() != null;
|
||||
|
||||
// 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...
|
||||
assert fetchParentAsFetch.getFetchParent().getNavigablePath().equals( parentParentPath );
|
||||
|
||||
// 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
|
||||
// );
|
||||
if ( fetchParentAsFetch.getFetchParent() instanceof Fetch ) {
|
||||
return new BiDirectionalFetchImpl(
|
||||
fetchParent.getNavigablePath().append( fetchable.getFetchableName() ),
|
||||
fetchParent,
|
||||
fetchParentAsFetch
|
||||
);
|
||||
}
|
||||
else {
|
||||
// return new RootBiDirectionalFetchImpl(
|
||||
// new NavigablePath( fetchable.getJavaTypeDescriptor().getJavaType().getName() ),
|
||||
// fetchable.getJavaTypeDescriptor(),
|
||||
// new NavigablePath( fetchable.getNavigableName() )
|
||||
// );
|
||||
}
|
||||
}
|
||||
}
|
||||
assert fetchParentAsFetch instanceof EntityResult;
|
||||
|
||||
// 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
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue