ResultSet mapping
- Implemented support for embeddable (composite) fetch paths
This commit is contained in:
parent
2050e366fe
commit
626031f31c
|
@ -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 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
}
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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 + ")";
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
}
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
|
||||
}
|
||||
}
|
|
@ -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
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,6 +61,8 @@ public interface Fetch extends DomainResultGraphNode {
|
|||
return true;
|
||||
}
|
||||
|
||||
DomainResult<?> asResult(DomainResultCreationState creationState);
|
||||
|
||||
/**
|
||||
* Create the assembler for this fetch
|
||||
*/
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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> {
|
||||
|
||||
}
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue