ResultSet mapping

- Implemented support for embeddable (composite) fetch paths
This commit is contained in:
Steve Ebersole 2020-08-14 15:38:07 -05:00
parent 2050e366fe
commit 626031f31c
44 changed files with 1542 additions and 283 deletions

View File

@ -22,23 +22,18 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.BootLogging;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.MutableObject;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.RuntimeMetamodels;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
import org.hibernate.query.EntityIdentifierNavigablePath;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.internal.FetchMementoBasicStandard;
import org.hibernate.query.internal.ImplicitModelPartResultMemento;
import org.hibernate.query.internal.FetchMementoJpa;
import org.hibernate.query.internal.ModelPartResultMementoBasicImpl;
import org.hibernate.query.internal.NamedResultSetMappingMementoImpl;
import org.hibernate.query.internal.ResultMementoBasicStandard;
import org.hibernate.query.internal.ResultMementoEntityStandard;
import org.hibernate.query.internal.ResultMementoEntityJpa;
import org.hibernate.query.internal.ResultMementoInstantiationStandard;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.FetchMemento;
@ -47,7 +42,6 @@ import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.named.ResultMemento;
import org.hibernate.query.named.ResultMementoBasic;
import org.hibernate.query.named.ResultMementoInstantiation.ArgumentMemento;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
@ -197,6 +191,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
}
this.argumentResultDescriptors = CollectionHelper.arrayList( columnResults.length );
//noinspection ForLoopReplaceableByForEach
for ( int i = 0; i < columnResults.length; i++ ) {
final ColumnResult columnResult = columnResults[i];
final JpaColumnResultDescriptor argumentResultDescriptor = new JpaColumnResultDescriptor(
@ -234,13 +229,14 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
* @see javax.persistence.EntityResult
*/
public static class EntityResultDescriptor implements ResultDescriptor {
@SuppressWarnings( { "FieldCanBeLocal", "FieldMayBeFinal", "unused" } )
private String resultSetMappingName;
private final NavigablePath navigablePath;
private final String entityName;
private final String discriminatorColumn;
private final Map<String, AttributeFetchDescriptor> fetchMappings;
private final Map<String, AttributeFetchDescriptor> explicitFetchMappings;
public EntityResultDescriptor(
EntityResult entityResult,
@ -252,15 +248,15 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
this.navigablePath = new NavigablePath( entityName );
this.fetchMappings = new HashMap<>();
this.explicitFetchMappings = new HashMap<>();
for ( int i = 0; i < entityResult.fields().length; i++ ) {
final FieldResult fieldResult = entityResult.fields()[ i ];
final AttributeFetchDescriptor existing = fetchMappings.get( fieldResult.name() );
final AttributeFetchDescriptor existing = explicitFetchMappings.get( fieldResult.name() );
if ( existing != null ) {
existing.addColumn( fieldResult );
}
else {
fetchMappings.put(
explicitFetchMappings.put(
fieldResult.name(),
AttributeFetchDescriptor.from( navigablePath, entityName, fieldResult, context )
);
@ -272,9 +268,6 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
public ResultMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
final EntityMappingType entityDescriptor = runtimeMetamodels.getEntityMappingType( entityName );
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
final MutableObject<ResultMemento> identifierMementoReference = new MutableObject<>();
final ResultMementoBasic discriminatorMemento = resolveDiscriminatorMemento(
entityDescriptor,
@ -283,69 +276,16 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
);
final Map<String, FetchMemento> fetchMementos = new HashMap<>();
entityDescriptor.visitAttributeMappings(
attributeMapping -> {
final String fetchableName = attributeMapping.getFetchableName();
final String attrNameName = attributeMapping.getAttributeName();
final boolean isIdentifier = ResultsHelper.isIdentifier(
identifierMapping,
fetchableName,
attrNameName
);
final AttributeFetchDescriptor fetchDescriptor = fetchMappings.get( fetchableName );
if ( isIdentifier ) {
final ResultMemento idResultMemento;
final EntityIdentifierNavigablePath idPath = new EntityIdentifierNavigablePath( navigablePath );
if ( fetchDescriptor == null ) {
final AttributeFetchDescriptor idRoleFetchDescriptor = fetchMappings.get( EntityIdentifierMapping.ROLE_LOCAL_NAME );
if ( idRoleFetchDescriptor == null ) {
idResultMemento = ResultsHelper.implicitIdentifierResult( identifierMapping, idPath, resolutionContext );
}
else {
idResultMemento = idRoleFetchDescriptor.asResultMemento( idPath, resolutionContext );
}
}
else {
idResultMemento = fetchDescriptor.asResultMemento( idPath, resolutionContext );
}
identifierMementoReference.set( idResultMemento );
}
else {
final NavigablePath fetchPath = navigablePath.append( fetchableName );
final FetchMemento fetchMemento;
if ( fetchDescriptor == null ) {
fetchMemento = ResultsHelper.implicitFetch( attributeMapping, fetchPath, resolutionContext );
}
else {
fetchMemento = fetchDescriptor.resolve( resolutionContext );
}
fetchMementos.put( fetchableName, fetchMemento );
}
},
null
explicitFetchMappings.forEach(
(relativePath, fetchDescriptor) -> fetchMementos.put(
relativePath,
fetchDescriptor.resolve( resolutionContext )
)
);
if ( identifierMementoReference.isNotSet() ) {
final EntityIdentifierNavigablePath idPath = new EntityIdentifierNavigablePath( navigablePath );
identifierMementoReference.set( new ImplicitModelPartResultMemento( idPath, identifierMapping ) );
}
assert entityDescriptor.getNumberOfAttributeMappings() == fetchMementos.size();
assert identifierMementoReference.isSet();
return new ResultMementoEntityStandard(
return new ResultMementoEntityJpa(
entityDescriptor,
LockMode.READ,
identifierMementoReference.get(),
discriminatorMemento,
fetchMementos
);
@ -360,6 +300,10 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
return null;
}
if ( discriminatorColumn == null ) {
return null;
}
return new ModelPartResultMementoBasicImpl(
entityPath.append( EntityDiscriminatorMapping.ROLE_NAME ),
discriminatorMapping,
@ -376,7 +320,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
FieldResult fieldResult,
MetadataBuildingContext context) {
return new AttributeFetchDescriptor(
entityPath.append( fieldResult.name() ),
entityPath,
entityName,
fieldResult.name(),
fieldResult.column()
@ -386,30 +330,36 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
private final NavigablePath navigablePath;
private final String entityName;
private final String attributeName;
private final String relativeFetchPath;
private final List<String> columnNames;
private AttributeFetchDescriptor(
NavigablePath attributePath,
NavigablePath entityPath,
String entityName,
String attributeName,
String relativeFetchPath,
String columnName) {
this.navigablePath = attributePath;
final String[] names = relativeFetchPath.split( "\\." );
NavigablePath fetchPath = entityPath;
//noinspection ForLoopReplaceableByForEach
for ( int i = 0; i < names.length; i++ ) {
fetchPath = fetchPath.append( names[ i ] );
}
this.navigablePath = fetchPath;
this.entityName = entityName;
this.attributeName = attributeName;
this.relativeFetchPath = relativeFetchPath;
this.columnNames = new ArrayList<>();
columnNames.add( columnName );
}
private void addColumn(FieldResult fieldResult) {
if ( ! attributeName.equals( fieldResult.name() ) ) {
if ( ! relativeFetchPath.equals( fieldResult.name() ) ) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Passed FieldResult [%s, %s] does not match AttributeFetchMapping [%s]",
fieldResult.name(),
fieldResult.column(),
attributeName
relativeFetchPath
)
);
}
@ -424,8 +374,9 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
final ModelPart subPart = entityMapping.findSubPart( attributeName, null );
final ModelPart subPart = entityMapping.findSubPart( relativeFetchPath, null );
//noinspection StatementWithEmptyBody
if ( subPart == null ) {
// throw an exception
}
@ -438,35 +389,14 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
}
throw new NotYetImplementedFor6Exception(
"Only support for basic-valued model-parts have been implemented : " + attributeName + " [" + subPart + "]"
"Only support for basic-valued model-parts have been implemented : " + relativeFetchPath
+ " [" + subPart + "]"
);
}
@Override
public FetchMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
final ModelPart subPart = entityMapping.findSubPart( attributeName, null );
if ( subPart == null ) {
// throw an exception
}
if ( subPart instanceof BasicValuedModelPart ) {
assert columnNames.size() == 1;
final BasicValuedModelPart basicPart = (BasicValuedModelPart) subPart;
return new FetchMementoBasicStandard(
navigablePath,
basicPart,
columnNames.get( 0 )
);
}
throw new NotYetImplementedFor6Exception(
"Only support for basic-valued model-parts have been implemented : " + attributeName + " [" + subPart + "]"
);
return new FetchMementoJpa( navigablePath, relativeFetchPath );
}
}
}

View File

@ -35,6 +35,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
@ -64,6 +65,7 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.results.graph.BiDirectionalFetch;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.EntityGraphTraversalState;
import org.hibernate.sql.results.graph.Fetch;
@ -72,11 +74,13 @@ import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResult;
import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
import org.jboss.logging.Logger;
import static org.hibernate.query.results.ResultsHelper.attributeName;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/**
@ -469,11 +473,44 @@ public class LoaderSelectBuilder {
List<Fetch> fetches,
List<String> bagRoles) {
return (fetchable, isKeyFetchable) -> {
NavigablePath panrentNavigablePath = fetchParent.getNavigablePath();
final NavigablePath parentNavigablePath = fetchParent.getNavigablePath();
final NavigablePath fetchablePath;
if ( isKeyFetchable ) {
panrentNavigablePath = new EntityIdentifierNavigablePath( panrentNavigablePath );
final EntityIdentifierMapping identifierMapping;
if ( fetchParent instanceof BiDirectionalFetch ) {
final BiDirectionalFetch parentAsBiDirectionalFetch = (BiDirectionalFetch) fetchParent;
final Fetchable biDirectionalFetchedMapping = parentAsBiDirectionalFetch.getFetchedMapping();
if ( biDirectionalFetchedMapping instanceof EntityValuedFetchable ) {
identifierMapping = ( (EntityValuedFetchable) biDirectionalFetchedMapping )
.getEntityMappingType()
.getIdentifierMapping();
}
else {
identifierMapping = null;
}
}
else {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
if ( fetchableContainer instanceof EntityValuedModelPart ) {
final EntityValuedModelPart entityValuedModelPart = (EntityValuedModelPart) fetchableContainer;
identifierMapping = entityValuedModelPart.getEntityMappingType().getIdentifierMapping();
}
else {
identifierMapping = null;
}
}
if ( identifierMapping != null ) {
fetchablePath = new EntityIdentifierNavigablePath( parentNavigablePath, attributeName( identifierMapping ) );
}
else {
fetchablePath = parentNavigablePath.append( fetchable.getFetchableName() );
}
}
else {
fetchablePath = parentNavigablePath.append( fetchable.getFetchableName() );
}
final NavigablePath fetchablePath = panrentNavigablePath.append( fetchable.getFetchableName() );
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
fetchablePath,

View File

@ -12,13 +12,69 @@ import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
* @author Andrea Boriero
*/
public class EntityIdentifierNavigablePath extends NavigablePath {
private final String identifierAttributeName;
public EntityIdentifierNavigablePath(NavigablePath parent) {
public EntityIdentifierNavigablePath(NavigablePath parent, String identifierAttributeName) {
super( parent, EntityIdentifierMapping.ROLE_LOCAL_NAME );
this.identifierAttributeName = identifierAttributeName;
}
@Override
public String getLocalName() {
return EntityIdentifierMapping.ROLE_LOCAL_NAME;
}
@Override
public int hashCode() {
return getParent().getFullPath().hashCode();
}
@Override
public boolean equals(Object other) {
if ( other == null ) {
return false;
}
if ( other == this ) {
return true;
}
if ( ! ( other instanceof NavigablePath ) ) {
return false;
}
final NavigablePath otherPath = (NavigablePath) other;
if ( getFullPath().equals( ( (NavigablePath) other ).getFullPath() ) ) {
return true;
}
if ( getParent() == null ) {
if ( otherPath.getParent() != null ) {
return false;
}
//noinspection RedundantIfStatement
if ( localNamesMatch( otherPath) ) {
return true;
}
return false;
}
if ( otherPath.getParent() == null ) {
return false;
}
return getParent().equals( otherPath.getParent() )
&& localNamesMatch( otherPath );
}
private boolean localNamesMatch(NavigablePath otherPath) {
final String otherLocalName = otherPath.getLocalName();
return otherLocalName.equals( getLocalName() )
|| otherLocalName.equals( identifierAttributeName );
}
}

View File

@ -134,15 +134,34 @@ public class NavigablePath implements DotIdentifierSequence {
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
public boolean equals(Object other) {
if ( this == other ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
if ( other instanceof EntityIdentifierNavigablePath ) {
final EntityIdentifierNavigablePath otherPath = (EntityIdentifierNavigablePath) other;
return otherPath.equals( this );
}
if ( ! ( other instanceof NavigablePath ) ) {
return false;
}
final NavigablePath other = (NavigablePath) o;
return Objects.equals( getFullPath(), other.getFullPath() );
final NavigablePath otherPath = (NavigablePath) other;
// todo (6.0) : checking the full paths is definitely better performance
// But I'm not sure it is correct in all cases. Take cases referencing
// an identifier at some level - the actual EntityIdentifierNavigablePath
// subclass has special handling for one path using the "role name" (`"{id}"`)
// while the other might instead use the attribute name
// return Objects.equals( getFullPath(), otherPath.getFullPath() );
if ( getParent() == null ) {
return otherPath.getParent() == null;
}
return getParent().equals( otherPath.getParent() )
&& getLocalName().equals( otherPath.getLocalName() );
}
}

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.query.internal;
import java.util.function.BiFunction;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class FetchBuilderJpa implements FetchBuilder {
private final NavigablePath navigablePath;
private final String attributePath;
public FetchBuilderJpa(NavigablePath navigablePath, String attributePath) {
this.navigablePath = navigablePath;
this.attributePath = attributePath;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
assert fetchPath.equals( navigablePath );
assert fetchPath.getFullPath().endsWith( attributePath );
final FetchableContainer container = parent.getReferencedMappingContainer();
final Fetchable subPart = (Fetchable) container.findSubPart( fetchPath.getLocalName(), null );
return subPart.generateFetch(
parent,
fetchPath,
FetchTiming.IMMEDIATE,
true,
LockMode.READ,
null,
domainResultCreationState
);
}
}

View File

@ -9,8 +9,6 @@ package org.hibernate.query.internal;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.FetchMementoBasic;
import org.hibernate.query.results.FetchBuilder;
@ -41,16 +39,6 @@ public class FetchMementoBasicStandard implements FetchMementoBasic {
return navigablePath;
}
@Override
public ModelPart getReferencedModelPart() {
return fetchedAttribute;
}
@Override
public MappingType getMappingType() {
return fetchedAttribute.getPartMappingType();
}
@Override
public FetchBuilder resolve(
Parent parent,

View File

@ -0,0 +1,48 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.internal;
import java.util.function.Consumer;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.results.FetchBuilder;
/**
* @author Steve Ebersole
*/
public class FetchMementoJpa implements FetchMemento {
private final NavigablePath fetchPath;
private final String attributePath;
public FetchMementoJpa(NavigablePath fetchPath, String attributePath) {
this.fetchPath = fetchPath;
this.attributePath = attributePath;
}
@Override
public FetchBuilder resolve(
Parent parent,
Consumer<String> querySpaceConsumer, ResultSetMappingResolutionContext context) {
final String[] names = attributePath.split( "\\." );
NavigablePath fetchPath = parent.getNavigablePath();
//noinspection ForLoopReplaceableByForEach
for ( int i = 0; i < names.length; i++ ) {
fetchPath = fetchPath.append( names[ i ] );
}
return new FetchBuilderJpa( fetchPath, attributePath );
}
@Override
public NavigablePath getNavigablePath() {
return fetchPath;
}
}

View File

@ -9,7 +9,6 @@ package org.hibernate.query.internal;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.results.FetchBuilder;
@ -27,11 +26,6 @@ public class ImplicitAttributeFetchMemento implements FetchMemento {
this.attributeMapping = attributeMapping;
}
@Override
public MappingType getMappingType() {
return attributeMapping.getPartMappingType();
}
@Override
public FetchBuilder resolve(
Parent parent,
@ -45,8 +39,4 @@ public class ImplicitAttributeFetchMemento implements FetchMemento {
return navigablePath;
}
@Override
public AttributeMapping getReferencedModelPart() {
return attributeMapping;
}
}

View File

@ -8,12 +8,15 @@ package org.hibernate.query.internal;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.ModelPartResultMemento;
import org.hibernate.query.named.ModelPartResultMementoBasic;
import org.hibernate.query.results.ImplicitModelPartResultBuilder;
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderBasic;
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderEmbeddable;
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderEntity;
import org.hibernate.query.results.ResultBuilder;
/**
@ -33,19 +36,22 @@ public class ImplicitModelPartResultMemento implements ModelPartResultMemento {
return navigablePath;
}
@Override
public ModelPart getReferencedModelPart() {
return referencedModelPart;
}
@Override
public ResultBuilder resolve(
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
return new ImplicitModelPartResultBuilder(
navigablePath,
null,
referencedModelPart
);
if ( referencedModelPart instanceof BasicValuedModelPart ) {
return new ImplicitModelPartResultBuilderBasic( navigablePath, (BasicValuedModelPart) referencedModelPart );
}
if ( referencedModelPart instanceof EmbeddableValuedModelPart ) {
return new ImplicitModelPartResultBuilderEmbeddable( navigablePath, (EmbeddableValuedModelPart) referencedModelPart );
}
if ( referencedModelPart instanceof EntityValuedModelPart ) {
return new ImplicitModelPartResultBuilderEntity( navigablePath, (EntityValuedModelPart) referencedModelPart );
}
throw new IllegalStateException( "Unknown type of model part : "+ referencedModelPart );
}
}

View File

@ -13,7 +13,6 @@ import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.ModelPartResultMementoBasic;
import org.hibernate.query.results.ResultBuilderBasicValued;
import org.hibernate.query.results.complete.CompleteResultBuilderBasicModelPart;
import org.hibernate.query.results.complete.CompleteResultBuilderBasicValuedStandard;
/**
* @author Steve Ebersole
@ -37,11 +36,6 @@ public class ModelPartResultMementoBasicImpl implements ModelPartResultMementoBa
return navigablePath;
}
@Override
public BasicValuedModelPart getReferencedModelPart() {
return modelPart;
}
@Override
public ResultBuilderBasicValued resolve(
Consumer<String> querySpaceConsumer,

View File

@ -0,0 +1,90 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.internal;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.named.ResultMementoBasic;
import org.hibernate.query.named.ResultMementoEntity;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultBuilderBasicValued;
import org.hibernate.query.results.ResultBuilderEntityValued;
import org.hibernate.query.results.complete.CompleteResultBuilderEntityJpa;
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderBasic;
/**
* @author Steve Ebersole
*/
public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento.Parent {
private final NavigablePath navigablePath;
private final EntityMappingType entityDescriptor;
private final LockMode lockMode;
// private final ResultMemento identifierMemento;
private final ResultMementoBasic discriminatorMemento;
private final Map<String, FetchMemento> explicitFetchMementoMap;
public ResultMementoEntityJpa(
EntityMappingType entityDescriptor,
LockMode lockMode,
ResultMementoBasic discriminatorMemento,
Map<String, FetchMemento> explicitFetchMementoMap) {
this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() );
this.entityDescriptor = entityDescriptor;
this.lockMode = lockMode;
this.discriminatorMemento = discriminatorMemento;
this.explicitFetchMementoMap = explicitFetchMementoMap;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public ResultBuilderEntityValued resolve(
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
final ResultBuilderBasicValued discriminatorResultBuilder;
if ( discriminatorMapping == null ) {
assert discriminatorMemento == null;
discriminatorResultBuilder = null;
}
else {
if ( discriminatorMemento != null ) {
discriminatorResultBuilder = discriminatorMemento.resolve( querySpaceConsumer, context );
}
else {
discriminatorResultBuilder = new ImplicitModelPartResultBuilderBasic( navigablePath, discriminatorMapping );
}
}
final HashMap<String, FetchBuilder> explicitFetchBuilderMap = new HashMap<>();
explicitFetchMementoMap.forEach(
(relativePath, fetchMemento) -> explicitFetchBuilderMap.put(
relativePath,
fetchMemento.resolve(this, querySpaceConsumer, context )
)
);
return new CompleteResultBuilderEntityJpa(
navigablePath,
entityDescriptor,
lockMode,
discriminatorResultBuilder,
explicitFetchBuilderMap
);
}
}

View File

@ -12,7 +12,6 @@ import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.named.ResultMemento;
@ -54,16 +53,6 @@ public class ResultMementoEntityStandard implements ResultMementoEntity, FetchMe
return navigablePath;
}
@Override
public EntityMappingType getReferencedModelPart() {
return entityDescriptor;
}
@Override
public ManagedMappingType getMappingType() {
return entityDescriptor;
}
@Override
public ResultBuilderEntityValued resolve(
Consumer<String> querySpaceConsumer,

View File

@ -8,8 +8,6 @@ package org.hibernate.query.named;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.results.FetchBuilder;
@ -21,17 +19,8 @@ public interface FetchMemento extends ModelPartReferenceMemento {
* The parent node for the fetch
*/
interface Parent extends ModelPartReferenceMemento {
/**
* The entity descriptor that is the base for this path/parent
*/
ManagedMappingType getMappingType();
}
/**
* The mapping descriptor for the fetchable
*/
MappingType getMappingType();
/**
* Resolve the fetch-memento into the result-graph-node builder
*/

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.query.named;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
/**
@ -21,8 +20,4 @@ public interface ModelPartReferenceMemento extends ResultMappingMementoNode {
*/
NavigablePath getNavigablePath();
/**
* The referenced domain model part
*/
ModelPart getReferencedModelPart();
}

View File

@ -6,12 +6,8 @@
*/
package org.hibernate.query.named;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
/**
* @author Steve Ebersole
*/
public interface ModelPartResultMementoBasic extends ModelPartResultMemento, ResultMementoBasic {
@Override
BasicValuedModelPart getReferencedModelPart();
}

View File

@ -15,8 +15,14 @@ import java.util.function.Function;
import org.hibernate.Internal;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.EntityIdentifierNavigablePath;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.results.dynamic.LegacyFetchResolver;
@ -34,10 +40,14 @@ import org.hibernate.sql.results.ResultsLogger;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.FetchableContainer;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.results.ResultsHelper.attributeName;
/**
* @author Steve Ebersole
*/
@ -58,6 +68,9 @@ public class DomainResultCreationStateImpl
private final LegacyFetchResolverImpl legacyFetchResolver;
private final SessionFactoryImplementor sessionFactory;
private final Stack<Function<String, FetchBuilder>> fetchBuilderResolverStack = new StandardStack<>( fetchableName -> null );
private final Stack<NavigablePath> relativePathStack = new StandardStack<>();
private boolean processingKeyFetches = false;
public DomainResultCreationStateImpl(
String stateIdentifier,
@ -101,6 +114,26 @@ public class DomainResultCreationStateImpl
return jdbcResultsMetadata;
}
public void pushExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver) {
fetchBuilderResolverStack.push( resolver );
}
public Function<String, FetchBuilder> popExplicitFetchMementoResolver() {
return fetchBuilderResolverStack.pop();
}
@SuppressWarnings( "unused" )
public void withExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver, Runnable runnable) {
pushExplicitFetchMementoResolver( resolver );
try {
runnable.run();
}
finally {
final Function<String, FetchBuilder> popped = popExplicitFetchMementoResolver();
assert popped == resolver;
}
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DomainResultCreationState
@ -263,7 +296,81 @@ public class DomainResultCreationStateImpl
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
throw new UnsupportedOperationException();
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
final List<Fetch> fetches = CollectionHelper.arrayList( fetchableContainer.getNumberOfFetchables() );
boolean previous = this.processingKeyFetches;
this.processingKeyFetches = true;
if ( fetchableContainer instanceof EntityValuedFetchable ) {
final EntityValuedFetchable entityValuedFetchable = (EntityValuedFetchable) fetchableContainer;
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
relativePathStack.push(
new EntityIdentifierNavigablePath(
relativePathStack.getCurrent(),
attributeName( identifierMapping )
)
);
try {
entityValuedFetchable.getEntityMappingType().visitKeyFetchables(
fetchable -> {
// depends whether these fetchables are the identifier mapping or
// the identifier sub-attribuates (if composite)
final String fetchableName = fetchable.getFetchableName();
final NavigablePath fetchPath = fetchParent.getNavigablePath().append( fetchableName );
final NavigablePath relativePath = relativePathStack.isEmpty()
? new NavigablePath( fetchableName )
: relativePathStack.getCurrent().append( fetchableName );
},
null
);
}
finally {
this.processingKeyFetches = previous;
this.relativePathStack.pop();
}
}
fetchableContainer.visitFetchables(
fetchable -> {
final String fetchableName = fetchable.getFetchableName();
final NavigablePath fetchPath = fetchParent.getNavigablePath().append( fetchableName );
final NavigablePath relativePath = relativePathStack.isEmpty()
? new NavigablePath( fetchableName )
: relativePathStack.getCurrent().append( fetchableName );
relativePathStack.push( relativePath );
try {
final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack
.getCurrent()
.apply( relativePath.getFullPath() );
final FetchBuilder fetchBuilder = explicitFetchBuilder != null
? explicitFetchBuilder
: ResultsHelper.implicitFetchBuilder( fetchPath, fetchable );
final Fetch fetch = fetchBuilder.buildFetch(
fetchParent,
fetchPath,
jdbcResultsMetadata,
(s, s2) -> {
throw new UnsupportedOperationException();
},
this
);
fetches.add( fetch );
}
finally {
relativePathStack.pop();
}
},
null
);
return fetches;
}
}

View File

@ -13,6 +13,7 @@ import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.results.implicit.ImplicitFetchBuilder;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
@ -23,7 +24,7 @@ import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
*
* @author Steve Ebersole
*/
public class ImplicitAttributeFetchBuilder implements FetchBuilder {
public class ImplicitAttributeFetchBuilder implements FetchBuilder, ImplicitFetchBuilder {
private final NavigablePath navigablePath;
private final AttributeMapping attributeMapping;

View File

@ -1,55 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results;
import java.util.function.BiFunction;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class ImplicitModelPartResultBuilder implements ResultBuilder {
private final NavigablePath navigablePath;
private final String alias;
private final ModelPart referencedModelPart;
public ImplicitModelPartResultBuilder(
NavigablePath navigablePath,
String alias,
ModelPart referencedModelPart) {
this.navigablePath = navigablePath;
this.alias = alias;
this.referencedModelPart = referencedModelPart;
}
@Override
public DomainResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl impl = ResultsHelper.impl( domainResultCreationState );
ResultsHelper.impl( domainResultCreationState ).disallowPositionalSelections();
;
return referencedModelPart.createDomainResult(
navigablePath,
impl.getFromClauseAccess().resolveTableGroup(
navigablePath,
np -> impl.getFromClauseAccess().getTableGroup( navigablePath.getParent() )
),
alias,
domainResultCreationState
);
}
}

View File

@ -0,0 +1,27 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results;
import java.util.function.BiFunction;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public interface ResultBuilderEmbeddable extends ResultBuilder {
@Override
EmbeddableResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState);
}

View File

@ -6,7 +6,11 @@
*/
package org.hibernate.query.results;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
@ -14,13 +18,23 @@ import org.hibernate.query.EntityIdentifierNavigablePath;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.internal.ImplicitAttributeFetchMemento;
import org.hibernate.query.internal.ImplicitModelPartResultMemento;
import org.hibernate.query.internal.ModelPartResultMementoBasicImpl;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.named.ModelPartResultMemento;
import org.hibernate.query.named.ResultMemento;
import org.hibernate.query.results.implicit.ImplicitFetchBuilder;
import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic;
import org.hibernate.query.results.implicit.ImplicitFetchBuilderEmbeddable;
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderEntity;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
/**
* @author Steve Ebersole
@ -70,11 +84,36 @@ public class ResultsHelper {
return false;
}
public static ResultMemento implicitIdentifierResult(
// public static ResultMemento implicitIdentifierResult(
// EntityIdentifierMapping identifierMapping,
// EntityIdentifierNavigablePath idPath,
// ResultSetMappingResolutionContext resolutionContext) {
// return new ImplicitModelPartResultMemento( idPath, identifierMapping );
// }
public static DomainResult implicitIdentifierResult(
EntityIdentifierMapping identifierMapping,
EntityIdentifierNavigablePath idPath,
DomainResultCreationState creationState) {
final DomainResultCreationStateImpl creationStateImpl = impl( creationState );
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( idPath.getParent() );
return identifierMapping.createDomainResult(
idPath,
tableGroup,
null,
creationState
);
}
public static ModelPartResultMemento implicitEntityResult(
String entityName,
ResultSetMappingResolutionContext resolutionContext) {
return new ImplicitModelPartResultMemento( idPath, identifierMapping );
final SessionFactoryImplementor sessionFactory = resolutionContext.getSessionFactory();
final EntityMappingType entityMappingType = resolutionContext.getSessionFactory()
.getRuntimeMetamodels()
.getEntityMappingType( entityName );
return new ImplicitModelPartResultMemento( new NavigablePath( entityName ), entityMappingType );
}
public static FetchMemento implicitFetch(
@ -83,4 +122,48 @@ public class ResultsHelper {
ResultSetMappingResolutionContext resolutionContext) {
return new ImplicitAttributeFetchMemento( attributePath, attributeMapping );
}
public static ResultBuilder implicitEntityResultBuilder(
Class<?> resultMappingClass,
ResultSetMappingResolutionContext resolutionContext) {
final EntityMappingType entityMappingType = resolutionContext
.getSessionFactory()
.getRuntimeMetamodels()
.getEntityMappingType( resultMappingClass );
return new ImplicitModelPartResultBuilderEntity( entityMappingType );
}
public static ImplicitFetchBuilder implicitFetchBuilder(NavigablePath fetchPath, Fetchable fetchable) {
if ( fetchable instanceof BasicValuedModelPart ) {
final BasicValuedModelPart basicValuedFetchable = (BasicValuedModelPart) fetchable;
return new ImplicitFetchBuilderBasic( fetchPath, basicValuedFetchable );
}
if ( fetchable instanceof EmbeddableValuedFetchable ) {
final EmbeddableValuedFetchable embeddableValuedFetchable = (EmbeddableValuedFetchable) fetchable;
return new ImplicitFetchBuilderEmbeddable( fetchPath, embeddableValuedFetchable );
}
if ( fetchable instanceof EntityValuedFetchable ) {
final EntityValuedFetchable entityValuedFetchable = (EntityValuedFetchable) fetchable;
throw new NotYetImplementedFor6Exception( "Support for implicit entity-valued fetches is not yet implemented" );
}
throw new UnsupportedOperationException();
}
public static String attributeName(EntityIdentifierMapping identifierMapping) {
return identifierMapping instanceof SingleAttributeIdentifierMapping
? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName()
: null;
}
public static DomainResult convertIdFetchToResult(Fetch fetch, DomainResultCreationState creationState) {
final EntityIdentifierMapping idMapping = (EntityIdentifierMapping) fetch.getFetchedMapping();
if ( fetch instanceof BasicFetch ) {
final BasicFetch<?> basicFetch = (BasicFetch<?>) fetch;
}
return null;
}
}

View File

@ -0,0 +1,122 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.complete;
import java.util.HashMap;
import java.util.function.BiFunction;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultBuilderBasicValued;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* CompleteResultBuilderEntityValued implementation specific to JPA. In JPA
* mappings, fetches contains also entity-identifier-related fetches - so we will
* need to look for that one here in the fetches and handle it specially.
*
* This differs from Hibernate's specific mapping declarations which split identifier related
* fetches separately
*
* @author Steve Ebersole
*/
public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEntityValued {
private final NavigablePath navigablePath;
private final EntityMappingType entityDescriptor;
private final LockMode lockMode;
private final ResultBuilderBasicValued discriminatorResultBuilder;
private final HashMap<String, FetchBuilder> explicitFetchBuilderMap;
public CompleteResultBuilderEntityJpa(
NavigablePath navigablePath,
EntityMappingType entityDescriptor,
LockMode lockMode,
ResultBuilderBasicValued discriminatorResultBuilder,
HashMap<String, FetchBuilder> explicitFetchBuilderMap) {
this.navigablePath = navigablePath;
this.entityDescriptor = entityDescriptor;
this.lockMode = lockMode;
this.discriminatorResultBuilder = discriminatorResultBuilder;
this.explicitFetchBuilderMap = explicitFetchBuilderMap;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public EntityMappingType getReferencedPart() {
return entityDescriptor;
}
@Override
public EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl impl = ResultsHelper.impl( domainResultCreationState );
impl.disallowPositionalSelections();
impl.pushExplicitFetchMementoResolver( explicitFetchBuilderMap::get );
try {
// we just want it added to the registry
impl.getFromClauseAccess().resolveTableGroup(
navigablePath,
np -> entityDescriptor.createRootTableGroup(
navigablePath,
null,
false,
lockMode,
impl.getSqlAliasBaseManager(),
impl.getSqlAstCreationState().getSqlExpressionResolver(),
() -> predicate -> {},
impl.getSqlAstCreationState().getCreationContext()
)
);
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
final BasicResult<?> discriminatorResult;
if ( discriminatorMapping == null ) {
assert discriminatorResultBuilder == null;
discriminatorResult = null;
}
else {
assert discriminatorResultBuilder != null;
discriminatorResult = discriminatorResultBuilder.buildResult(
jdbcResultsMetadata,
resultPosition,
legacyFetchResolver,
domainResultCreationState
);
}
return new EntityResultImpl(
navigablePath,
entityDescriptor,
null,
lockMode,
discriminatorResult,
domainResultCreationState
);
}
finally {
impl.popExplicitFetchMementoResolver();
}
}
}

View File

@ -111,25 +111,8 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
entityDescriptor,
null,
lockMode,
identifierResult,
discriminatorResult,
fetchParent -> {
final List<Fetch> fetches = new ArrayList<>( fetchBuilderMap.size() );
fetchBuilderMap.forEach(
(fetchableName, fetchBuilder) -> fetches.add(
fetchBuilder.buildFetch(
fetchParent,
navigablePath.append( fetchableName ),
jdbcResultsMetadata,
legacyFetchResolver,
domainResultCreationState
)
)
);
return fetches;
}
domainResultCreationState
);
}
}

View File

@ -7,16 +7,20 @@
package org.hibernate.query.results.complete;
import java.util.List;
import java.util.function.Function;
import org.hibernate.LockMode;
import org.hibernate.internal.util.MutableObject;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
import org.hibernate.query.EntityIdentifierNavigablePath;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.graph.entity.EntityInitializer;
@ -38,22 +42,57 @@ public class EntityResultImpl implements EntityResult {
private final String resultAlias;
private final LockMode lockMode;
@SuppressWarnings( { "PointlessNullCheck" } )
public EntityResultImpl(
NavigablePath navigablePath,
EntityValuedModelPart entityValuedModelPart,
String resultAlias,
LockMode lockMode,
DomainResult identifierResult,
BasicResult discriminatorResult,
Function<FetchParent,List<Fetch>> fetchesProducer) {
BasicResult<?> discriminatorResult,
DomainResultCreationState creationState) {
this.navigablePath = navigablePath;
this.entityValuedModelPart = entityValuedModelPart;
this.resultAlias = resultAlias;
this.lockMode = lockMode;
this.identifierResult = identifierResult;
this.discriminatorResult = discriminatorResult;
this.fetches = fetchesProducer.apply( this );
this.fetches = creationState.visitFetches( this );
final EntityIdentifierMapping identifierMapping = entityValuedModelPart
.getEntityMappingType()
.getIdentifierMapping();
final String idAttributeName = identifierMapping instanceof SingleAttributeIdentifierMapping
? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName()
: null;
final MutableObject<Fetch> idFetchRef = new MutableObject<>();
for ( int i = 0; i < this.fetches.size(); i++ ) {
final Fetch fetch = this.fetches.get( i );
final String fetchLocalName = fetch.getNavigablePath().getLocalName();
if ( fetchLocalName.equals( EntityIdentifierMapping.ROLE_LOCAL_NAME )
|| ( idAttributeName != null && fetchLocalName.equals( idAttributeName ) ) ) {
// we found the id fetch
idFetchRef.set( fetch );
this.fetches.remove( i );
break;
}
}
if ( idFetchRef.isNotSet() ) {
identifierResult = ResultsHelper.implicitIdentifierResult(
identifierMapping,
new EntityIdentifierNavigablePath(
navigablePath,
ResultsHelper.attributeName( identifierMapping )
),
creationState
);
}
else {
this.identifierResult = idFetchRef.get().asResult( creationState );
}
}
@Override

View File

@ -0,0 +1,15 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import org.hibernate.query.results.FetchBuilder;
/**
* @author Steve Ebersole
*/
public interface ImplicitFetchBuilder extends FetchBuilder {
}

View File

@ -0,0 +1,96 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import java.util.function.BiFunction;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.ConvertibleModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/**
* @author Steve Ebersole
*/
public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder {
private final NavigablePath fetchPath;
private final BasicValuedModelPart fetchable;
public ImplicitFetchBuilderBasic(NavigablePath fetchPath, BasicValuedModelPart fetchable) {
this.fetchPath = fetchPath;
this.fetchable = fetchable;
}
@Override
public BasicFetch<?> buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState );
final TableGroup parentTableGroup = creationStateImpl
.getFromClauseAccess()
.getTableGroup( parent.getNavigablePath() );
final String column = fetchable.getMappedColumnExpression();
final String table = fetchable.getContainingTableExpression();
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( column );
final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition );
final Expression expression = creationStateImpl.resolveSqlExpression(
createColumnReferenceKey( parentTableGroup.getTableReference( table ), column ),
processingState -> new SqlSelectionImpl( valuesArrayPosition, fetchable )
);
creationStateImpl.resolveSqlSelection(
expression,
fetchable.getJavaTypeDescriptor(),
domainResultCreationState.getSqlAstCreationState()
.getCreationContext()
.getSessionFactory()
.getTypeConfiguration()
);
return new BasicFetch<>(
valuesArrayPosition,
parent,
fetchPath,
fetchable,
// todo (6.0) - we don't know
true,
( (ConvertibleModelPart) fetchable ).getValueConverter(),
FetchTiming.IMMEDIATE,
domainResultCreationState
);
}
@Override
public String toString() {
return "ImplicitFetchBuilderBasic(" + fetchPath + ")";
}
}

View File

@ -0,0 +1,112 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import java.util.function.BiFunction;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import static org.hibernate.query.results.ResultsHelper.impl;
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/**
* @author Steve Ebersole
*/
public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
private final NavigablePath fetchPath;
private final EmbeddableValuedFetchable fetchable;
public ImplicitFetchBuilderEmbeddable(
NavigablePath fetchPath,
EmbeddableValuedFetchable fetchable) {
this.fetchPath = fetchPath;
this.fetchable = fetchable;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState creationState) {
final DomainResultCreationStateImpl creationStateImpl = impl( creationState );
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().resolveTableGroup(
fetchPath,
navigablePath -> {
final TableGroup parentTableGroup = creationStateImpl
.getFromClauseAccess()
.getTableGroup( parent.getNavigablePath() );
final TableGroupJoin tableGroupJoin = fetchable.createTableGroupJoin(
fetchPath,
parentTableGroup,
null,
SqlAstJoinType.INNER,
LockMode.READ,
creationStateImpl
);
return tableGroupJoin.getJoinedGroup();
}
);
fetchable.visitColumns(
(table, column, isColumnFormula, jdbcMapping) -> {
final TableReference tableReference = tableGroup.getTableReference( table );
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( column );
final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition );
final Expression expression = creationStateImpl.resolveSqlExpression(
createColumnReferenceKey( tableReference, column ),
processingState -> new SqlSelectionImpl(
valuesArrayPosition,
jdbcMapping
)
);
creationStateImpl.resolveSqlSelection(
expression,
jdbcMapping.getJavaTypeDescriptor(),
creationStateImpl.getSessionFactory().getTypeConfiguration()
);
}
);
return fetchable.generateFetch(
parent,
fetchPath,
FetchTiming.IMMEDIATE,
true,
LockMode.READ,
null,
creationState
);
}
@Override
public String toString() {
return "ImplicitFetchBuilderEmbeddable(" + fetchPath + ")";
}
}

View File

@ -0,0 +1,15 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import org.hibernate.query.results.ResultBuilder;
/**
* @author Steve Ebersole
*/
public interface ImplicitModelPartResultBuilder extends ResultBuilder {
}

View File

@ -0,0 +1,48 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import java.util.function.BiFunction;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.ResultBuilderBasicValued;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class ImplicitModelPartResultBuilderBasic
implements ImplicitModelPartResultBuilder, ResultBuilderBasicValued {
private final NavigablePath navigablePath;
private final BasicValuedModelPart modelPart;
public ImplicitModelPartResultBuilderBasic(NavigablePath navigablePath, BasicValuedModelPart modelPart) {
this.navigablePath = navigablePath;
this.modelPart = modelPart;
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState );
final TableGroup tableGroup = creationStateImpl
.getFromClauseAccess()
.getTableGroup( navigablePath.getParent() );
return (BasicResult<?>) modelPart.createDomainResult( navigablePath, tableGroup, null, domainResultCreationState );
}
}

View File

@ -0,0 +1,86 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import java.util.function.BiFunction;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.ResultBuilderEmbeddable;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class ImplicitModelPartResultBuilderEmbeddable
implements ImplicitModelPartResultBuilder, ResultBuilderEmbeddable {
private final NavigablePath navigablePath;
private final EmbeddableValuedModelPart modelPart;
public ImplicitModelPartResultBuilderEmbeddable(
NavigablePath navigablePath,
EmbeddableValuedModelPart modelPart) {
this.navigablePath = navigablePath;
this.modelPart = modelPart;
}
@Override
public EmbeddableResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState );
creationStateImpl.disallowPositionalSelections();
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().resolveTableGroup(
navigablePath,
np -> {
if ( navigablePath.getParent() == null ) {
throw new IllegalStateException(
"Could not determine LHS for implicit embeddable result builder - " + navigablePath
);
}
final TableGroup parentTableGroup = creationStateImpl
.getFromClauseAccess()
.getTableGroup( navigablePath.getParent() );
final TableGroupJoin tableGroupJoin = modelPart.createTableGroupJoin(
navigablePath,
parentTableGroup,
null,
SqlAstJoinType.INNER,
LockMode.READ,
creationStateImpl
);
parentTableGroup.addTableGroupJoin( tableGroupJoin );
return tableGroupJoin.getJoinedGroup();
}
);
return (EmbeddableResult) modelPart.createDomainResult(
navigablePath,
tableGroup,
null,
domainResultCreationState
);
}
}

View File

@ -0,0 +1,81 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.results.implicit;
import java.util.function.BiFunction;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.ResultBuilderEntityValued;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class ImplicitModelPartResultBuilderEntity
implements ImplicitModelPartResultBuilder, ResultBuilderEntityValued {
private final NavigablePath navigablePath;
private final EntityValuedModelPart modelPart;
public ImplicitModelPartResultBuilderEntity(
NavigablePath navigablePath,
EntityValuedModelPart modelPart) {
this.navigablePath = navigablePath;
this.modelPart = modelPart;
}
public ImplicitModelPartResultBuilderEntity(EntityMappingType entityMappingType) {
this( new NavigablePath( entityMappingType.getEntityName() ), entityMappingType );
}
@Override
public EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl creationStateImpl = ResultsHelper.impl( domainResultCreationState );
creationStateImpl.disallowPositionalSelections();
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().resolveTableGroup(
navigablePath,
np -> {
if ( navigablePath.getParent() != null ) {
return creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
}
return modelPart.getEntityMappingType().createRootTableGroup(
navigablePath,
null,
false,
LockMode.READ,
creationStateImpl.getSqlAliasBaseGenerator(),
creationStateImpl,
() -> predicate -> {
},
creationStateImpl.getSqlAstCreationState().getCreationContext()
);
}
);
return (EntityResult) modelPart.createDomainResult(
navigablePath,
tableGroup,
null,
domainResultCreationState
);
}
}

View File

@ -81,6 +81,16 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
return sqlString;
}
@Override
public String getResultMappingName() {
return resultSetMappingName;
}
@Override
public Class<?> getResultMappingClass() {
return resultSetMappingClass;
}
@Override
public NamedNativeQueryMemento makeCopy(String name) {
return new NamedNativeQueryMementoImpl(
@ -108,8 +118,7 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
@Override
public NativeQueryImplementor toQuery(SharedSessionContractImplementor session) {
//noinspection unchecked
return toQuery( session, (Class) null );
return new NativeQueryImpl( this, session );
}
@Override

View File

@ -63,6 +63,7 @@ import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.Builders;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ResultSetMappingImpl;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
import org.hibernate.query.results.dynamic.DynamicResultBuilderInstantiation;
@ -129,7 +130,29 @@ public class NativeQueryImpl<R>
this.occurrenceOrderedParamList = parameterInterpretation.getOccurrenceOrderedParameters();
this.parameterBindings = QueryParameterBindingsImpl.from( parameterMetadata, session.getFactory() );
this.resultSetMapping = new ResultSetMappingImpl( sqlString );
if ( memento.getResultMappingName() != null ) {
this.resultSetMapping = new ResultSetMappingImpl( memento.getResultMappingName() );
final NamedResultSetMappingMemento resultSetMappingMemento = getSessionFactory().getQueryEngine()
.getNamedQueryRepository()
.getResultSetMappingMemento( memento.getResultMappingName() );
resultSetMappingMemento.resolve(
resultSetMapping,
querySpace -> addSynchronizedQuerySpace( querySpace ),
this
);
}
else if ( memento.getResultMappingClass() != null ) {
this.resultSetMapping = new ResultSetMappingImpl( memento.getResultMappingName() );
resultSetMapping.addResultBuilder(
ResultsHelper.implicitEntityResultBuilder(
memento.getResultMappingClass(),
this
)
);
}
else {
this.resultSetMapping = new ResultSetMappingImpl( sqlString );
}
applyOptions( memento );
}

View File

@ -8,6 +8,8 @@ package org.hibernate.query.sql.spi;
import java.util.Set;
import javax.persistence.SqlResultSetMapping;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -32,6 +34,18 @@ public interface NamedNativeQueryMemento extends NamedQueryMemento {
*/
Set<String> getQuerySpaces();
/**
* An explicit ResultSet mapping by name
*
* @see SqlResultSetMapping#name
*/
String getResultMappingName();
/**
* An implicit entity mapping by entity class
*/
Class<?> getResultMappingClass();
/**
* Convert the memento into an untyped executable query
*/

View File

@ -57,4 +57,11 @@ public interface BiDirectionalFetch extends Fetch {
* `p.address.owner` and `p.address.owner.address` respectively
*/
NavigablePath getReferencedPath();
@Override
default DomainResult<?> asResult(DomainResultCreationState creationState) {
throw new UnsupportedOperationException(
"Entity Fetch references conversion to DomainResult not supported"
);
}
}

View File

@ -61,6 +61,8 @@ public interface Fetch extends DomainResultGraphNode {
return true;
}
DomainResult<?> asResult(DomainResultCreationState creationState);
/**
* Create the assembler for this fetch
*/

View File

@ -10,7 +10,9 @@ 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.query.results.ResultsHelper;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -69,6 +71,18 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
return fetchTiming == FetchTiming.IMMEDIATE;
}
@Override
public DomainResult<?> asResult(DomainResultCreationState creationState) {
return valuedMapping.createDomainResult(
navigablePath,
ResultsHelper.impl( creationState )
.getFromClauseAccess()
.getTableGroup( fetchParent.getNavigablePath() ),
getResultVariable(),
creationState
);
}
@Override
public FetchParent getFetchParent() {
return fetchParent;

View File

@ -8,6 +8,9 @@ package org.hibernate.sql.results.graph.collection.internal;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
@ -39,6 +42,18 @@ public abstract class CollectionFetch implements Fetch {
return fetchedAttribute;
}
@Override
public DomainResult<?> asResult(DomainResultCreationState creationState) {
return fetchedAttribute.createDomainResult(
fetchedPath,
ResultsHelper.impl( creationState )
.getFromClauseAccess()
.getTableGroup( fetchParent.getNavigablePath() ),
null,
creationState
);
}
@Override
public NavigablePath getNavigablePath() {
return fetchedPath;

View File

@ -0,0 +1,16 @@
/*
* 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.graph.embeddable;
import org.hibernate.sql.results.graph.DomainResult;
/**
* @author Steve Ebersole
*/
public interface EmbeddableResult<T> extends EmbeddableResultGraphNode, DomainResult<T> {
}

View File

@ -11,11 +11,13 @@ import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.ast.SqlAstJoinType;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.results.graph.AbstractFetchParent;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -30,6 +32,8 @@ import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
* @author Steve Ebersole
*/
public class EmbeddableFetchImpl extends AbstractFetchParent implements EmbeddableResultGraphNode, Fetch {
private final EmbeddableValuedFetchable embeddedPartDescriptor;
private final FetchParent fetchParent;
private final FetchTiming fetchTiming;
private final boolean hasTableGroup;
@ -44,6 +48,7 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
boolean nullable,
DomainResultCreationState creationState) {
super( embeddedPartDescriptor.getEmbeddableTypeDescriptor(), navigablePath );
this.embeddedPartDescriptor = embeddedPartDescriptor;
this.fetchParent = fetchParent;
this.fetchTiming = fetchTiming;
@ -102,6 +107,18 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
return getReferencedMappingContainer();
}
@Override
public DomainResult<?> asResult(DomainResultCreationState creationState) {
return embeddedPartDescriptor.createDomainResult(
getNavigablePath(),
ResultsHelper.impl( creationState )
.getFromClauseAccess()
.getTableGroup( fetchParent.getNavigablePath() ),
null,
creationState
);
}
@Override
public EmbeddableMappingType getReferencedMappingType() {
return getFetchContainer();

View File

@ -20,16 +20,16 @@ import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.DomainResultGraphNode;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResult;
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class EmbeddableResultImpl<T> extends AbstractFetchParent implements EmbeddableResultGraphNode, DomainResult<T> {
public class EmbeddableResultImpl<T> extends AbstractFetchParent implements EmbeddableResultGraphNode, DomainResult<T>, EmbeddableResult<T> {
private final String resultVariable;
private final boolean containsAnyNonScalars;

View File

@ -27,6 +27,8 @@ import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.query.results.ResultsHelper.attributeName;
/**
* AbstractFetchParent sub-class for entity-valued graph nodes
*
@ -72,7 +74,10 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
identifierResult = null;
if ( identifierMapping instanceof SingleAttributeIdentifierMapping ) {
identifierMapping.createDomainResult(
new EntityIdentifierNavigablePath( navigablePath ),
new EntityIdentifierNavigablePath(
navigablePath,
attributeName( identifierMapping )
),
entityTableGroup,
null,
creationState
@ -84,7 +89,10 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
}
else {
identifierResult = identifierMapping.createDomainResult(
new EntityIdentifierNavigablePath( navigablePath ),
new EntityIdentifierNavigablePath(
navigablePath,
attributeName( identifierMapping )
),
entityTableGroup,
null,
creationState
@ -142,7 +150,10 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
attributeMapping -> {
if ( attributeMapping instanceof ToOneAttributeMapping ) {
( (ToOneAttributeMapping) attributeMapping ).getForeignKeyDescriptor().createDomainResult(
new EntityIdentifierNavigablePath( navigablePath ),
new EntityIdentifierNavigablePath(
navigablePath,
attributeName( identifierMapping )
),
entityTableGroup,
null,
creationState
@ -150,7 +161,10 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
}
else {
attributeMapping.createDomainResult(
new EntityIdentifierNavigablePath( navigablePath ),
new EntityIdentifierNavigablePath(
navigablePath,
attributeName( identifierMapping )
),
entityTableGroup,
null,
creationState

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.sql.results.graph.entity;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
/**
@ -16,4 +18,9 @@ public interface EntityFetch extends EntityResultGraphNode, Fetch {
default boolean containsAnyNonScalarResults() {
return true;
}
@Override
default DomainResult<?> asResult(DomainResultCreationState creationState) {
throw new UnsupportedOperationException( "EntityFetch -> DomainResult not supported" );
}
}

View File

@ -47,7 +47,8 @@ import static org.hamcrest.Matchers.notNullValue;
DiscriminatedRoot.class,
DiscriminatedSubType1.class,
DiscriminatedSubType2.class,
EntityOfBasics.class
EntityOfBasics.class,
EntityWithEmbedded.class
}
)
@ServiceRegistry(
@ -230,6 +231,38 @@ public class EntityResultTests extends BaseUsageTest {
);
}
@Test
public void testImplicitEmbeddedMapping(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityWithEmbedded result = (EntityWithEmbedded) session
.getNamedNativeQuery( EntityWithEmbedded.IMPLICIT )
.getSingleResult();
assertThat( result, notNullValue() );
assertThat( result.getId(), is( 1 ) );
assertThat( result.getCompoundName(), notNullValue() );
assertThat( result.getCompoundName().getFirstPart(), is( "hi" ) );
assertThat( result.getCompoundName().getSecondPart(), is( "there" ) );
}
);
}
@Test
public void testExplicitEmbeddedMapping(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final EntityWithEmbedded result = (EntityWithEmbedded) session
.getNamedNativeQuery( EntityWithEmbedded.EXPLICIT )
.getSingleResult();
assertThat( result, notNullValue() );
assertThat( result.getId(), is( 1 ) );
assertThat( result.getCompoundName(), notNullValue() );
assertThat( result.getCompoundName().getFirstPart(), is( "hi" ) );
assertThat( result.getCompoundName().getSecondPart(), is( "there" ) );
}
);
}
private static final Instant THEN = Instant.now( Clock.systemUTC() );
private static final Date THEN_TIMESTAMP = Timestamp.from( THEN );
private static final Date THEN_DATE = java.sql.Date.from( THEN );
@ -267,6 +300,16 @@ public class EntityResultTests extends BaseUsageTest {
entityOfBasics.setTheInstant( THEN );
session.save( entityOfBasics );
// embedded values
final EntityWithEmbedded entityWithEmbedded = new EntityWithEmbedded(
1,
new EntityWithEmbedded.CompoundName(
"hi",
"there"
)
);
session.persist( entityWithEmbedded );
}
);
}
@ -279,6 +322,8 @@ public class EntityResultTests extends BaseUsageTest {
session.createQuery( "delete DiscriminatedRoot" ).executeUpdate();
// converted values data
session.createQuery( "delete EntityOfBasics" ).executeUpdate();
// embedded values
session.createQuery( "delete EntityWithEmbedded" ).executeUpdate();
}
);
}

View File

@ -0,0 +1,131 @@
/*
* 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.orm.test.query.resultmapping;
import javax.persistence.Column;
import javax.persistence.Embeddable;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import javax.persistence.EntityResult;
import javax.persistence.FieldResult;
import javax.persistence.Id;
import javax.persistence.NamedNativeQuery;
import javax.persistence.SqlResultSetMapping;
import javax.persistence.Table;
import static org.hibernate.orm.test.query.resultmapping.EntityWithEmbedded.IMPLICIT;
/**
* @author Steve Ebersole
*/
@Entity
@Table( name = "entity_with_embedded" )
@SqlResultSetMapping(
name = IMPLICIT,
entities = @EntityResult( entityClass = EntityWithEmbedded.class )
)
@SqlResultSetMapping(
name = EntityWithEmbedded.EXPLICIT,
entities = @EntityResult(
entityClass = EntityWithEmbedded.class,
fields = {
@FieldResult( name = "id", column = "id_alias" ),
@FieldResult( name = "compoundName.firstPart", column = "name_first_part_alias" ),
@FieldResult( name = "compoundName.secondPart", column = "name_second_part_alias" )
}
)
)
@NamedNativeQuery(
name = EntityWithEmbedded.EXPLICIT,
query =
"select id as id_alias,"
+ " name_first_part as name_first_part_alias,"
+ " name_second_part as name_second_part_alias"
+ " from entity_with_embedded",
resultSetMapping = EntityWithEmbedded.EXPLICIT
)
@NamedNativeQuery(
name = IMPLICIT,
query =
"select id,"
+ " name_first_part,"
+ " name_second_part"
+ " from entity_with_embedded",
resultSetMapping = IMPLICIT
)
public class EntityWithEmbedded {
public static final String IMPLICIT = "entity-with-embedded-implicit";
public static final String EXPLICIT = "entity-with-embedded-explicit";
private Integer id;
private CompoundName compoundName;
public EntityWithEmbedded() {
}
public EntityWithEmbedded(Integer id, CompoundName compoundName) {
this.id = id;
this.compoundName = compoundName;
}
@Id
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
@Embedded
public CompoundName getCompoundName() {
return compoundName;
}
public void setCompoundName(CompoundName compoundName) {
this.compoundName = compoundName;
}
@Embeddable
public static class CompoundName {
private String firstPart;
private String secondPart;
public CompoundName() {
}
public CompoundName(String firstPart, String secondPart) {
this.firstPart = firstPart;
this.secondPart = secondPart;
}
@Column( name = "name_first_part" )
public String getFirstPart() {
return firstPart;
}
public void setFirstPart(String firstPart) {
this.firstPart = firstPart;
}
@Column( name = "name_second_part" )
public String getSecondPart() {
return secondPart;
}
public void setSecondPart(String secondPart) {
this.secondPart = secondPart;
}
@Override
public String toString() {
return firstPart + "." + secondPart;
}
}
}