Work on named-native query support
This commit is contained in:
parent
ae69a1aeb4
commit
c4445fbf5c
|
@ -67,6 +67,7 @@ public class ColumnTransformerTest extends BaseEntityManagerFunctionalTestCase {
|
|||
read = "money / 100",
|
||||
write = "? * 100"
|
||||
)
|
||||
// todo (6.0): needs a composite user type mechanism e.g. by providing a custom ComponentTuplizer/Instantiator
|
||||
private MonetaryAmount wallet;
|
||||
|
||||
//Getters and setters omitted for brevity
|
||||
|
|
|
@ -52,8 +52,8 @@ import javax.persistence.SqlResultSetMapping;
|
|||
@FieldResult(name = "name", column = "name"),
|
||||
@FieldResult(name = "model", column = "model"),
|
||||
@FieldResult(name = "speed", column = "speed"),
|
||||
@FieldResult(name = "captain.lastname", column = "lastn"),
|
||||
@FieldResult(name = "captain.firstname", column = "firstn"),
|
||||
@FieldResult(name = "captain.id.lastname", column = "lastn"),
|
||||
@FieldResult(name = "captain.id.firstname", column = "firstn"),
|
||||
@FieldResult(name = "dimensions.length", column = "length"),
|
||||
@FieldResult(name = "dimensions.width", column = "width"),
|
||||
}
|
||||
|
|
|
@ -15,6 +15,8 @@ import javax.persistence.NamedStoredProcedureQuery;
|
|||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.query.NamedProcedureCallDefinition;
|
||||
|
@ -23,8 +25,12 @@ import org.hibernate.cfg.annotations.QueryHintDefinition;
|
|||
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.procedure.internal.NamedCallableQueryMementoImpl;
|
||||
import org.hibernate.procedure.internal.Util;
|
||||
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
|
||||
import org.hibernate.procedure.spi.ParameterStrategy;
|
||||
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
|
||||
import org.hibernate.query.results.ResultSetMappingImpl;
|
||||
|
||||
import static org.hibernate.procedure.spi.NamedCallableQueryMemento.ParameterMemento;
|
||||
|
||||
|
@ -44,7 +50,7 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin
|
|||
private final ParameterDefinitions parameterDefinitions;
|
||||
private final Map<String, Object> hints;
|
||||
|
||||
NamedProcedureCallDefinitionImpl(NamedStoredProcedureQuery annotation) {
|
||||
public NamedProcedureCallDefinitionImpl(NamedStoredProcedureQuery annotation) {
|
||||
this.registeredName = annotation.name();
|
||||
this.procedureName = annotation.procedureName();
|
||||
this.hints = new QueryHintDefinition( registeredName, annotation.hints() ).getHintsMap();
|
||||
|
@ -84,12 +90,45 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin
|
|||
final boolean specifiesResultClasses = resultClasses != null && resultClasses.length > 0;
|
||||
final boolean specifiesResultSetMappings = resultSetMappings != null && resultSetMappings.length > 0;
|
||||
|
||||
// if ( specifiesResultClasses ) {
|
||||
// Util.resolveResultClasses(
|
||||
// new Util.ResultClassesResolutionContext() {
|
||||
ResultSetMappingImpl resultSetMapping = new ResultSetMappingImpl( registeredName );
|
||||
|
||||
if ( specifiesResultClasses ) {
|
||||
Util.resolveResultSetMappingClasses(
|
||||
resultClasses,
|
||||
resultSetMapping,
|
||||
collectedQuerySpaces::add,
|
||||
new ResultSetMappingResolutionContext() {
|
||||
@Override
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public SessionFactoryImplementor getSessionFactory() {
|
||||
// return sessionFactory;
|
||||
// public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
|
||||
// Collections.addAll( collectedQueryReturns, queryReturns );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void addQuerySpaces(String... spaces) {
|
||||
// Collections.addAll( collectedQuerySpaces, spaces );
|
||||
// }
|
||||
}
|
||||
);
|
||||
}
|
||||
else if ( specifiesResultSetMappings ) {
|
||||
Util.resolveResultSetMappingNames(
|
||||
resultSetMappings,
|
||||
resultSetMapping,
|
||||
collectedQuerySpaces::add,
|
||||
new ResultSetMappingResolutionContext() {
|
||||
@Override
|
||||
public SessionFactoryImplementor getSessionFactory() {
|
||||
return sessionFactory;
|
||||
}
|
||||
|
||||
// @Override
|
||||
// public NamedResultSetMappingMemento findResultSetMapping(String name) {
|
||||
// return sessionFactory.getQueryEngine().getNamedObjectRepository().getResultSetMappingMemento( name );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
|
@ -101,47 +140,28 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin
|
|||
// public void addQuerySpaces(String... spaces) {
|
||||
// Collections.addAll( collectedQuerySpaces, spaces );
|
||||
// }
|
||||
// },
|
||||
// resultClasses
|
||||
// );
|
||||
// }
|
||||
// else if ( specifiesResultSetMappings ) {
|
||||
// Util.resolveResultSetMappings(
|
||||
// new Util.ResultSetMappingResolutionContext() {
|
||||
// @Override
|
||||
// public SessionFactoryImplementor getSessionFactory() {
|
||||
// return sessionFactory;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public ResultSetMappingDescriptor findResultSetMapping(String name) {
|
||||
// return sessionFactory.getQueryEngine().getNamedQueryRepository().getResultSetMappingMemento( name );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
|
||||
// Collections.addAll( collectedQueryReturns, queryReturns );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void addQuerySpaces(String... spaces) {
|
||||
// Collections.addAll( collectedQuerySpaces, spaces );
|
||||
// }
|
||||
// },
|
||||
// resultSetMappings
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// return new NamedCallableQueryMementoImpl(
|
||||
// getRegistrationName(),
|
||||
// procedureName,
|
||||
// collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] ),
|
||||
// parameterDefinitions.getParameterStrategy(),
|
||||
// parameterDefinitions.toMementos( sessionFactory ),
|
||||
// collectedQuerySpaces,
|
||||
// hints
|
||||
// );
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return new NamedCallableQueryMementoImpl(
|
||||
getRegistrationName(),
|
||||
procedureName,
|
||||
parameterDefinitions.getParameterStrategy(),
|
||||
parameterDefinitions.toMementos( sessionFactory ),
|
||||
resultSetMappings,
|
||||
resultClasses,
|
||||
collectedQuerySpaces,
|
||||
false,
|
||||
null,
|
||||
CacheMode.IGNORE,
|
||||
FlushMode.AUTO,
|
||||
false,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
hints
|
||||
);
|
||||
}
|
||||
|
||||
static class ParameterDefinitions {
|
||||
|
@ -234,19 +254,19 @@ public class NamedProcedureCallDefinitionImpl implements NamedProcedureCallDefin
|
|||
|
||||
@SuppressWarnings("UnnecessaryUnboxing")
|
||||
public ParameterMemento toMemento(SessionFactoryImplementor sessionFactory) {
|
||||
final boolean initialPassNullSetting = explicitPassNullSetting != null
|
||||
? explicitPassNullSetting.booleanValue()
|
||||
: sessionFactory.getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||
// todo (6.0): figure out how to handle this
|
||||
// final boolean initialPassNullSetting = explicitPassNullSetting != null
|
||||
// ? explicitPassNullSetting.booleanValue()
|
||||
// : sessionFactory.getSessionFactoryOptions().isProcedureParameterNullPassingEnabled();
|
||||
|
||||
// return new ParameterMemento(
|
||||
// position,
|
||||
// name,
|
||||
// parameterMode,
|
||||
// type,
|
||||
// sessionFactory.getTypeResolver().heuristicType( type.getName() ),
|
||||
// initialPassNullSetting
|
||||
// );
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
return new NamedCallableQueryMementoImpl.ParameterMementoImpl(
|
||||
position,
|
||||
name,
|
||||
parameterMode,
|
||||
type,
|
||||
sessionFactory.getTypeConfiguration().getBasicTypeForJavaType( type )
|
||||
// ,initialPassNullSetting
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -540,7 +540,7 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
+ " did not reference FetchableContainer"
|
||||
);
|
||||
}
|
||||
navigablePath = fetchParentMemento.getNavigablePath().append( propertyPathParts[ i ] );
|
||||
navigablePath = navigablePath.append( propertyPathParts[ i ] );
|
||||
fetchable = (Fetchable) ( (FetchableContainer) fetchable ).findSubPart( propertyPathParts[i], null );
|
||||
}
|
||||
|
||||
|
|
|
@ -18,17 +18,22 @@ import javax.persistence.FieldResult;
|
|||
import javax.persistence.SqlResultSetMapping;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.RuntimeMetamodels;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.internal.FetchMementoBasicStandard;
|
||||
import org.hibernate.query.internal.ImplicitAttributeFetchMemento;
|
||||
import org.hibernate.query.internal.ModelPartResultMementoBasicImpl;
|
||||
import org.hibernate.query.internal.NamedResultSetMappingMementoImpl;
|
||||
import org.hibernate.query.internal.ResultMementoBasicStandard;
|
||||
|
@ -41,7 +46,8 @@ 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.complete.CompleteResultBuilderBasicModelPart;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.FetchableContainer;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
|
@ -330,36 +336,32 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
private final NavigablePath navigablePath;
|
||||
|
||||
private final String entityName;
|
||||
private final String relativeFetchPath;
|
||||
private final String propertyPath;
|
||||
private final String[] propertyPathParts;
|
||||
private final List<String> columnNames;
|
||||
|
||||
private AttributeFetchDescriptor(
|
||||
NavigablePath entityPath,
|
||||
String entityName,
|
||||
String relativeFetchPath,
|
||||
String propertyPath,
|
||||
String columnName) {
|
||||
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.relativeFetchPath = relativeFetchPath;
|
||||
this.propertyPath = propertyPath;
|
||||
this.propertyPathParts = propertyPath.split( "\\." );
|
||||
this.navigablePath = entityPath;
|
||||
this.columnNames = new ArrayList<>();
|
||||
columnNames.add( columnName );
|
||||
}
|
||||
|
||||
private void addColumn(FieldResult fieldResult) {
|
||||
if ( ! relativeFetchPath.equals( fieldResult.name() ) ) {
|
||||
if ( ! propertyPath.equals( fieldResult.name() ) ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Passed FieldResult [%s, %s] does not match AttributeFetchMapping [%s]",
|
||||
fieldResult.name(),
|
||||
fieldResult.column(),
|
||||
relativeFetchPath
|
||||
propertyPath
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -374,7 +376,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
|
||||
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
|
||||
|
||||
final ModelPart subPart = entityMapping.findSubPart( relativeFetchPath, null );
|
||||
final ModelPart subPart = entityMapping.findSubPart( propertyPath, null );
|
||||
|
||||
//noinspection StatementWithEmptyBody
|
||||
if ( subPart == null ) {
|
||||
|
@ -389,7 +391,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Only support for basic-valued model-parts have been implemented : " + relativeFetchPath
|
||||
"Only support for basic-valued model-parts have been implemented : " + propertyPath
|
||||
+ " [" + subPart + "]"
|
||||
);
|
||||
}
|
||||
|
@ -399,15 +401,34 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
|
||||
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
|
||||
|
||||
final ModelPart subPart = entityMapping.resolveSubPart( navigablePath );
|
||||
NavigablePath navigablePath = this.navigablePath.append( propertyPathParts[ 0 ] );
|
||||
ModelPart subPart = entityMapping.findSubPart(
|
||||
propertyPathParts[ 0 ],
|
||||
null
|
||||
);
|
||||
|
||||
for ( int i = 1; i < propertyPathParts.length; i++ ) {
|
||||
if ( ! ( subPart instanceof ModelPartContainer ) ) {
|
||||
throw new MappingException(
|
||||
"Non-terminal property path [" + navigablePath.getFullPath()
|
||||
+ " did not reference FetchableContainer"
|
||||
);
|
||||
}
|
||||
navigablePath = navigablePath.append( propertyPathParts[ i ] );
|
||||
subPart = ( (ModelPartContainer) subPart ).findSubPart( propertyPathParts[i], null );
|
||||
}
|
||||
|
||||
if ( subPart instanceof BasicValuedModelPart ) {
|
||||
assert columnNames.size() == 1;
|
||||
final BasicValuedModelPart basicPart = (BasicValuedModelPart) subPart;
|
||||
|
||||
return new FetchMementoBasicStandard( navigablePath, basicPart, columnNames.get( 0 ) );
|
||||
}
|
||||
else if ( subPart instanceof EntityValuedModelPart ) {
|
||||
return new ImplicitAttributeFetchMemento( navigablePath, (AttributeMapping) subPart );
|
||||
}
|
||||
throw new NotYetImplementedFor6Exception(
|
||||
"Only support for basic-valued model-parts have been implemented : " + relativeFetchPath
|
||||
"Only support for basic-valued model-parts have been implemented : " + propertyPath
|
||||
+ " [" + subPart + "]"
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.annotations.CacheModeType;
|
|||
import org.hibernate.annotations.FlushModeType;
|
||||
import org.hibernate.annotations.QueryHints;
|
||||
import org.hibernate.boot.internal.NamedHqlQueryDefinitionImpl;
|
||||
import org.hibernate.boot.internal.NamedProcedureCallDefinitionImpl;
|
||||
import org.hibernate.boot.query.NamedNativeQueryDefinitionBuilder;
|
||||
import org.hibernate.boot.spi.MetadataBuildingContext;
|
||||
import org.hibernate.boot.query.NamedHqlQueryDefinition;
|
||||
|
@ -316,17 +317,15 @@ public abstract class QueryBinder {
|
|||
throw new AnnotationException( "A named query must have a name when used in class or package level" );
|
||||
}
|
||||
|
||||
throw new NotYetImplementedFor6Exception();
|
||||
// NamedProcedureCallDefinition.
|
||||
// final NamedProcedureCallDefinitionImpl def = new NamedProcedureCallDefinitionImpl( annotation );
|
||||
//
|
||||
// if (isDefault) {
|
||||
// context.getMetadataCollector().addDefaultNamedProcedureCall( def );
|
||||
// }
|
||||
// else {
|
||||
// context.getMetadataCollector().addNamedProcedureCallDefinition( def );
|
||||
// }
|
||||
// LOG.debugf( "Bound named stored procedure query : %s => %s", def.getRegistrationName(), def.getProcedureName() );
|
||||
final NamedProcedureCallDefinitionImpl def = new NamedProcedureCallDefinitionImpl( annotation );
|
||||
|
||||
if ( isDefault ) {
|
||||
context.getMetadataCollector().addDefaultNamedProcedureCall( def );
|
||||
}
|
||||
else {
|
||||
context.getMetadataCollector().addNamedProcedureCallDefinition( def );
|
||||
}
|
||||
LOG.debugf( "Bound named stored procedure query : %s => %s", def.getRegistrationName(), def.getProcedureName() );
|
||||
}
|
||||
|
||||
public static void bindSqlResultSetMappings(
|
||||
|
|
|
@ -72,8 +72,8 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
|||
DomainResultCreationState creationState) {
|
||||
return new BagInitializerProducer(
|
||||
attributeMapping,
|
||||
attributeMapping.getIdentifierDescriptor() == null ? null : attributeMapping.getIdentifierDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
attributeMapping.getIdentifierDescriptor() == null ? null : fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIdentifierDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ID.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -81,8 +81,8 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
|||
null,
|
||||
creationState
|
||||
),
|
||||
attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -105,8 +105,8 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
|||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState){
|
||||
if ( indexFetch == null ) {
|
||||
indexFetch = attributeMapping.getIdentifierDescriptor() == null ? null : attributeMapping.getIdentifierDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
indexFetch = attributeMapping.getIdentifierDescriptor() == null ? null : fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIdentifierDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ID.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -116,8 +116,8 @@ public abstract class AbstractBagSemantics<E> implements BagSemantics<Collection
|
|||
);
|
||||
}
|
||||
if ( elementFetch == null ) {
|
||||
elementFetch = attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
elementFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
|
|
@ -84,8 +84,8 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
|||
DomainResultCreationState creationState) {
|
||||
return new MapInitializerProducer(
|
||||
attributeMapping,
|
||||
attributeMapping.getIndexDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -93,8 +93,8 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
|||
null,
|
||||
creationState
|
||||
),
|
||||
attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -117,8 +117,8 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
|||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState){
|
||||
if ( indexFetch == null ) {
|
||||
indexFetch = attributeMapping.getIndexDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
indexFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -128,8 +128,8 @@ public abstract class AbstractMapSemantics<MKV extends Map<K,V>, K, V> implement
|
|||
);
|
||||
}
|
||||
if ( elementFetch == null ) {
|
||||
elementFetch = attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
elementFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
|
|
@ -57,8 +57,8 @@ public abstract class AbstractSetSemantics<SE extends Set<E>,E> implements Colle
|
|||
DomainResultCreationState creationState) {
|
||||
return new SetInitializerProducer(
|
||||
attributeMapping,
|
||||
attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
|
|
@ -105,8 +105,8 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
|||
DomainResultCreationState creationState) {
|
||||
return new ArrayInitializerProducer(
|
||||
attributeMapping,
|
||||
attributeMapping.getIndexDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -114,8 +114,8 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
|||
null,
|
||||
creationState
|
||||
),
|
||||
attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -138,8 +138,8 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
|||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState){
|
||||
if ( indexFetch == null ) {
|
||||
indexFetch = attributeMapping.getIndexDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
indexFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -149,8 +149,8 @@ public class StandardArraySemantics<E> implements CollectionSemantics<E[], E> {
|
|||
);
|
||||
}
|
||||
if ( elementFetch == null ) {
|
||||
elementFetch = attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
elementFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
|
|
@ -79,8 +79,8 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
DomainResultCreationState creationState) {
|
||||
return new ListInitializerProducer(
|
||||
attributeMapping,
|
||||
attributeMapping.getIndexDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -88,8 +88,8 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
null,
|
||||
creationState
|
||||
),
|
||||
attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -112,8 +112,8 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
Fetch elementFetch,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( indexFetch == null ) {
|
||||
indexFetch = attributeMapping.getIndexDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
indexFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getIndexDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.INDEX.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
@ -123,8 +123,8 @@ public class StandardListSemantics<E> implements CollectionSemantics<List<E>, E>
|
|||
);
|
||||
}
|
||||
if ( elementFetch == null ) {
|
||||
elementFetch = attributeMapping.getElementDescriptor().generateFetch(
|
||||
fetchParent,
|
||||
elementFetch = fetchParent.generateFetchableFetch(
|
||||
attributeMapping.getElementDescriptor(),
|
||||
navigablePath.append( CollectionPart.Nature.ELEMENT.getName() ),
|
||||
FetchTiming.IMMEDIATE,
|
||||
selected,
|
||||
|
|
|
@ -102,8 +102,8 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
|
|||
fetchParent.getReferencedMappingContainer().visitFetchables(
|
||||
fetchable -> {
|
||||
final NavigablePath navigablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() );
|
||||
final Fetch fetch = fetchable.generateFetch(
|
||||
fetchParent,
|
||||
final Fetch fetch = fetchParent.generateFetchableFetch(
|
||||
fetchable,
|
||||
navigablePath,
|
||||
fetchable.getMappedFetchOptions().getTiming(),
|
||||
true,
|
||||
|
@ -322,8 +322,8 @@ public abstract class AbstractNaturalIdLoader<T> implements NaturalIdLoader<T> {
|
|||
fetchParent.getReferencedMappingContainer().visitFetchables(
|
||||
(fetchable) -> {
|
||||
final NavigablePath navigablePath = fetchParent.getNavigablePath().append( fetchable.getFetchableName() );
|
||||
final Fetch fetch = fetchable.generateFetch(
|
||||
fetchParent,
|
||||
final Fetch fetch = fetchParent.generateFetchableFetch(
|
||||
fetchable,
|
||||
navigablePath,
|
||||
fetchable.getMappedFetchOptions().getTiming(),
|
||||
true,
|
||||
|
|
|
@ -737,8 +737,8 @@ public class LoaderSelectBuilder {
|
|||
if ( changeFetchDepth ) {
|
||||
fetchDepth++;
|
||||
}
|
||||
final Fetch fetch = fetchable.generateFetch(
|
||||
fetchParent,
|
||||
final Fetch fetch = fetchParent.generateFetchableFetch(
|
||||
fetchable,
|
||||
fetchablePath,
|
||||
fetchTiming,
|
||||
joined,
|
||||
|
|
|
@ -19,6 +19,8 @@ import org.hibernate.NotYetImplementedFor6Exception;
|
|||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.engine.FetchStyle;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
|
@ -35,10 +37,13 @@ import org.hibernate.mapping.IndexedConsumer;
|
|||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.DiscriminatedAssociationAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.mapping.internal.SelectableMappingsImpl;
|
||||
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
|
@ -165,6 +170,67 @@ public class EmbeddableMappingType implements ManagedMappingType, SelectableMapp
|
|||
|
||||
}
|
||||
|
||||
private EmbeddableMappingType(
|
||||
EmbeddableValuedModelPart valueMapping,
|
||||
SelectableMappings selectableMappings,
|
||||
EmbeddableMappingType inverseMappingType,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
this.embeddableJtd = null;
|
||||
this.representationStrategy = inverseMappingType.representationStrategy;
|
||||
this.sessionFactory = inverseMappingType.sessionFactory;
|
||||
this.valueMapping = valueMapping;
|
||||
this.createEmptyCompositesEnabled = inverseMappingType.isCreateEmptyCompositesEnabled();
|
||||
this.selectableMappings = selectableMappings;
|
||||
creationProcess.registerInitializationCallback(
|
||||
"EmbeddableMappingType(" + inverseMappingType.getNavigableRole().getFullPath() + ".{inverse})#finishInitialization",
|
||||
() -> {
|
||||
if ( inverseMappingType.attributeMappings.isEmpty() ) {
|
||||
return false;
|
||||
}
|
||||
int currentIndex = 0;
|
||||
// We copy the attributes from the inverse mappings and replace the selection mappings
|
||||
for ( AttributeMapping attributeMapping : inverseMappingType.attributeMappings ) {
|
||||
if ( attributeMapping instanceof BasicValuedSingularAttributeMapping ) {
|
||||
final BasicValuedSingularAttributeMapping original = (BasicValuedSingularAttributeMapping) attributeMapping;
|
||||
final SelectableMapping selectableMapping = selectableMappings.getSelectable( currentIndex );
|
||||
attributeMapping = BasicValuedSingularAttributeMapping.withSelectableMapping( original, selectableMapping );
|
||||
currentIndex++;
|
||||
}
|
||||
else if ( attributeMapping instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping original = (ToOneAttributeMapping) attributeMapping;
|
||||
final ToOneAttributeMapping toOne = original.copy();
|
||||
final int offset = currentIndex;
|
||||
toOne.setIdentifyingColumnsTableExpression(
|
||||
selectableMappings.getSelectable( offset ).getContainingTableExpression()
|
||||
);
|
||||
toOne.setForeignKeyDescriptor(
|
||||
original.getForeignKeyDescriptor().withKeySelectionMapping(
|
||||
index -> selectableMappings.getSelectable( offset + index ),
|
||||
creationProcess
|
||||
)
|
||||
);
|
||||
|
||||
attributeMapping = toOne;
|
||||
currentIndex += attributeMapping.getJdbcTypeCount();
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException(
|
||||
"Only basic and to-one attributes are supported in composite fks" );
|
||||
}
|
||||
this.attributeMappings.add( attributeMapping );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public EmbeddableMappingType createInverseMappingType(
|
||||
EmbeddableValuedModelPart valueMapping,
|
||||
SelectableMappings selectableMappings,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
return new EmbeddableMappingType( valueMapping, selectableMappings, this, creationProcess );
|
||||
}
|
||||
|
||||
private boolean finishInitialization(
|
||||
Component bootDescriptor,
|
||||
CompositeType compositeType,
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
|
@ -27,6 +32,8 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
|||
|
||||
String getTargetTable();
|
||||
|
||||
ModelPart getKeyPart();
|
||||
|
||||
DomainResult createCollectionFetchDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
TableGroup tableGroup,
|
||||
|
@ -84,5 +91,12 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
|||
return visitTargetSelectables( 0, consumer );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a copy of this foreign key descriptor with the selectable mappings as provided by the given accessor.
|
||||
*/
|
||||
ForeignKeyDescriptor withKeySelectionMapping(
|
||||
IntFunction<SelectableMapping> selectableMappingAccess,
|
||||
MappingModelCreationProcess creationProcess);
|
||||
|
||||
AssociationKey getAssociationKey();
|
||||
}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.metamodel.mapping.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
|
@ -16,8 +19,10 @@ import org.hibernate.metamodel.mapping.SelectableMapping;
|
|||
import org.hibernate.metamodel.mapping.ordering.ast.DomainPath;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.expression.SqlTuple;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
|
@ -29,6 +34,77 @@ import org.hibernate.sql.ast.tree.select.SortSpecification;
|
|||
public abstract class AbstractDomainPath implements DomainPath {
|
||||
public static final String ELEMENT_TOKEN = "$element$";
|
||||
|
||||
@Override
|
||||
public SqlAstNode resolve(
|
||||
QuerySpec ast,
|
||||
TableGroup tableGroup,
|
||||
String modelPartName,
|
||||
SqlAstCreationState creationState) {
|
||||
return resolve(
|
||||
getReferenceModelPart(),
|
||||
ast,
|
||||
tableGroup,
|
||||
modelPartName,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
public Expression resolve(
|
||||
ModelPart referenceModelPart,
|
||||
QuerySpec ast,
|
||||
TableGroup tableGroup,
|
||||
String modelPartName,
|
||||
SqlAstCreationState creationState) {
|
||||
if ( referenceModelPart instanceof BasicValuedModelPart ) {
|
||||
final BasicValuedModelPart selection = (BasicValuedModelPart) referenceModelPart;
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( selection.getContainingTableExpression() );
|
||||
return creationState.getSqlExpressionResolver().resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
selection.getContainingTableExpression(),
|
||||
selection.getSelectionExpression()
|
||||
),
|
||||
sqlAstProcessingState -> new ColumnReference(
|
||||
tableReference,
|
||||
selection,
|
||||
creationState.getCreationContext().getSessionFactory()
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ( referenceModelPart instanceof EntityValuedModelPart ) {
|
||||
final ModelPart subPart;
|
||||
if ( ELEMENT_TOKEN.equals( modelPartName ) ) {
|
||||
subPart = ( (EntityValuedModelPart) referenceModelPart ).getEntityMappingType().getIdentifierMapping();
|
||||
}
|
||||
else {
|
||||
subPart = ( (EntityValuedModelPart) referenceModelPart ).findSubPart( modelPartName );
|
||||
}
|
||||
return resolve( subPart, ast, tableGroup, modelPartName, creationState );
|
||||
}
|
||||
else if ( referenceModelPart instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableValuedModelPart embeddableValuedModelPart = (EmbeddableValuedModelPart) referenceModelPart;
|
||||
if ( embeddableValuedModelPart.getFetchableName()
|
||||
.equals( modelPartName ) || ELEMENT_TOKEN.equals( modelPartName ) ) {
|
||||
final List<Expression> expressions = new ArrayList<>( embeddableValuedModelPart.getNumberOfFetchables() );
|
||||
embeddableValuedModelPart.visitFetchables(
|
||||
fetchable -> {
|
||||
expressions.add( resolve( fetchable, ast, tableGroup, modelPartName, creationState ) );
|
||||
},
|
||||
null
|
||||
);
|
||||
return new SqlTuple( expressions, embeddableValuedModelPart );
|
||||
}
|
||||
else {
|
||||
ModelPart subPart = embeddableValuedModelPart.findSubPart( modelPartName, null );
|
||||
assert subPart instanceof BasicValuedModelPart;
|
||||
return resolve( subPart, ast, tableGroup, modelPartName, creationState );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// sure it can happen
|
||||
throw new NotYetImplementedFor6Exception( "Ordering for " + referenceModelPart + " not supported" );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(
|
||||
QuerySpec ast,
|
||||
|
@ -97,7 +173,7 @@ public abstract class AbstractDomainPath implements DomainPath {
|
|||
}
|
||||
else {
|
||||
// sure it can happen
|
||||
throw new NotYetImplementedFor6Exception( "Ordering for " + getReferenceModelPart() + "not supported" );
|
||||
throw new NotYetImplementedFor6Exception( "Ordering for " + getReferenceModelPart() + " not supported" );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.metamodel.mapping.ConvertibleModelPart;
|
|||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
|
@ -101,6 +102,51 @@ public class BasicValuedSingularAttributeMapping
|
|||
}
|
||||
}
|
||||
|
||||
public static BasicValuedSingularAttributeMapping withSelectableMapping(
|
||||
BasicValuedModelPart original,
|
||||
SelectableMapping selectableMapping) {
|
||||
String attributeName = null;
|
||||
int stateArrayPosition = 0;
|
||||
StateArrayContributorMetadataAccess attributeMetadataAccess = null;
|
||||
BasicValueConverter<?, ?> valueConverter = null;
|
||||
PropertyAccess propertyAccess = null;
|
||||
ManagedMappingType declaringType = null;
|
||||
if ( original instanceof SingleAttributeIdentifierMapping ) {
|
||||
final SingleAttributeIdentifierMapping mapping = (SingleAttributeIdentifierMapping) original;
|
||||
attributeName = mapping.getAttributeName();
|
||||
attributeMetadataAccess = null;
|
||||
propertyAccess = mapping.getPropertyAccess();
|
||||
declaringType = mapping.findContainingEntityMapping();
|
||||
}
|
||||
else if ( original instanceof SingularAttributeMapping ) {
|
||||
final SingularAttributeMapping mapping = (SingularAttributeMapping) original;
|
||||
attributeName = mapping.getAttributeName();
|
||||
stateArrayPosition = mapping.getStateArrayPosition();
|
||||
attributeMetadataAccess = mapping.getAttributeMetadataAccess();
|
||||
propertyAccess = mapping.getPropertyAccess();
|
||||
declaringType = mapping.getDeclaringType();
|
||||
}
|
||||
if ( original instanceof ConvertibleModelPart ) {
|
||||
valueConverter = ( (ConvertibleModelPart) original ).getValueConverter();
|
||||
}
|
||||
return new BasicValuedSingularAttributeMapping(
|
||||
attributeName,
|
||||
original.getNavigableRole(),
|
||||
stateArrayPosition,
|
||||
attributeMetadataAccess,
|
||||
FetchStrategy.IMMEDIATE_JOIN,
|
||||
selectableMapping.getContainingTableExpression(),
|
||||
selectableMapping.getSelectionExpression(),
|
||||
selectableMapping.isFormula(),
|
||||
selectableMapping.getCustomReadExpression(),
|
||||
selectableMapping.getCustomWriteExpression(),
|
||||
valueConverter,
|
||||
selectableMapping.getJdbcMapping(),
|
||||
declaringType,
|
||||
propertyAccess
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return jdbcMapping;
|
||||
|
|
|
@ -16,11 +16,13 @@ import org.hibernate.engine.FetchTiming;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||
import org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl;
|
||||
|
@ -99,6 +101,31 @@ public class EmbeddedAttributeMapping
|
|||
this.embeddableMappingType = embeddableMappingType;
|
||||
}
|
||||
|
||||
// Constructor is only used for creating the inverse attribute mapping
|
||||
private EmbeddedAttributeMapping(
|
||||
SelectableMappings selectableMappings,
|
||||
EmbeddableValuedModelPart inverseModelPart,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
super( inverseModelPart.getFetchableName(), -1, null, inverseModelPart.getMappedFetchOptions(), null, null );
|
||||
|
||||
this.navigableRole = inverseModelPart.getNavigableRole().getParent().append( inverseModelPart.getFetchableName() );
|
||||
|
||||
this.tableExpression = selectableMappings.getSelectable( 0 ).getContainingTableExpression();
|
||||
this.embeddableMappingType = inverseModelPart.getEmbeddableTypeDescriptor().createInverseMappingType(
|
||||
this,
|
||||
selectableMappings,
|
||||
creationProcess
|
||||
);
|
||||
this.parentInjectionAttributePropertyAccess = null;
|
||||
}
|
||||
|
||||
public static EmbeddableValuedModelPart createInverseModelPart(
|
||||
EmbeddableValuedModelPart modelPart,
|
||||
SelectableMappings selectableMappings,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
return new EmbeddedAttributeMapping( selectableMappings, modelPart, creationProcess );
|
||||
}
|
||||
|
||||
@Override
|
||||
public EmbeddableMappingType getMappedType() {
|
||||
return getEmbeddableTypeDescriptor();
|
||||
|
|
|
@ -8,8 +8,11 @@ package org.hibernate.metamodel.mapping.internal;
|
|||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.mapping.IndexedConsumer;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
|
@ -19,7 +22,9 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
|
@ -27,11 +32,10 @@ import org.hibernate.query.NavigablePath;
|
|||
import org.hibernate.sql.ast.Clause;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
|
||||
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||
|
@ -47,7 +51,8 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
*/
|
||||
public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||
|
||||
private final EmbeddableValuedModelPart mappingType;
|
||||
private final EmbeddableValuedModelPart keyMappingType;
|
||||
private final EmbeddableValuedModelPart targetMappingType;
|
||||
private final String keyTable;
|
||||
private final SelectableMappings keySelectableMappings;
|
||||
private final String targetTable;
|
||||
|
@ -55,7 +60,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
private AssociationKey associationKey;
|
||||
|
||||
public EmbeddedForeignKeyDescriptor(
|
||||
EmbeddableValuedModelPart mappingType,
|
||||
EmbeddableValuedModelPart targetMappingType,
|
||||
String keyTable,
|
||||
SelectableMappings keySelectableMappings,
|
||||
String targetTable,
|
||||
|
@ -65,24 +70,45 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
this.keySelectableMappings = keySelectableMappings;
|
||||
this.targetTable = targetTable;
|
||||
this.targetSelectableMappings = targetSelectableMappings;
|
||||
this.mappingType = mappingType;
|
||||
this.targetMappingType = targetMappingType;
|
||||
this.keyMappingType = EmbeddedAttributeMapping.createInverseModelPart(
|
||||
targetMappingType,
|
||||
keySelectableMappings,
|
||||
creationProcess
|
||||
);
|
||||
|
||||
creationProcess.registerInitializationCallback(
|
||||
"Embedded (composite) FK descriptor " + mappingType.getNavigableRole(),
|
||||
"Embedded (composite) FK descriptor " + targetMappingType.getNavigableRole(),
|
||||
() -> {
|
||||
// todo (6.0) : how to make sure things we need are ready to go?
|
||||
// - e.g., here, we need access to the sub-attributes
|
||||
final List<AttributeMapping> subAttributes = mappingType.getEmbeddableTypeDescriptor().getAttributeMappings();
|
||||
final List<AttributeMapping> subAttributes = targetMappingType.getEmbeddableTypeDescriptor().getAttributeMappings();
|
||||
if ( subAttributes.isEmpty() ) {
|
||||
// todo (6.0) : ^^ for now, this is the only way we "know" that the embeddable has not been finalized yet
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private EmbeddedForeignKeyDescriptor(
|
||||
EmbeddedForeignKeyDescriptor original,
|
||||
String keyTable,
|
||||
SelectableMappings keySelectableMappings,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
this.keyTable = keyTable;
|
||||
this.keySelectableMappings = keySelectableMappings;
|
||||
this.targetTable = original.targetTable;
|
||||
this.targetSelectableMappings = original.targetSelectableMappings;
|
||||
this.targetMappingType = original.targetMappingType;
|
||||
this.keyMappingType = EmbeddedAttributeMapping.createInverseModelPart(
|
||||
targetMappingType,
|
||||
keySelectableMappings,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyTable() {
|
||||
return keyTable;
|
||||
|
@ -93,6 +119,22 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
return targetTable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForeignKeyDescriptor withKeySelectionMapping(
|
||||
IntFunction<SelectableMapping> selectableMappingAccess,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
SelectableMapping[] selectionMappings = new SelectableMapping[keySelectableMappings.getJdbcTypeCount()];
|
||||
for ( int i = 0; i < selectionMappings.length; i++ ) {
|
||||
selectionMappings[i] = selectableMappingAccess.apply( i );
|
||||
}
|
||||
return new EmbeddedForeignKeyDescriptor(
|
||||
this,
|
||||
selectionMappings[0].getContainingTableExpression(),
|
||||
new SelectableMappingsImpl( selectionMappings ),
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult createCollectionFetchDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
|
@ -103,7 +145,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
collectionPath,
|
||||
tableGroup,
|
||||
targetTable,
|
||||
targetSelectableMappings,
|
||||
targetMappingType,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
@ -112,7 +154,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
collectionPath,
|
||||
tableGroup,
|
||||
keyTable,
|
||||
keySelectableMappings,
|
||||
keyMappingType,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
@ -120,84 +162,70 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
|
||||
@Override
|
||||
public DomainResult createDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
return createDomainResult(
|
||||
collectionPath,
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
keyTable,
|
||||
keySelectableMappings,
|
||||
keyMappingType,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult createDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
boolean isKeyReferringSide,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( isKeyReferringSide ) {
|
||||
return createDomainResult(
|
||||
collectionPath,
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
keyTable,
|
||||
keySelectableMappings,
|
||||
keyMappingType,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
else {
|
||||
return createDomainResult(
|
||||
collectionPath,
|
||||
navigablePath,
|
||||
tableGroup,
|
||||
targetTable,
|
||||
targetSelectableMappings,
|
||||
targetMappingType,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private DomainResult createDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
String columnContainingTable,
|
||||
SelectableMappings selectableMappings,
|
||||
EmbeddableValuedModelPart modelPart,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( columnContainingTable );
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
|
||||
final List<SqlSelection> sqlSelections = new ArrayList<>( selectableMappings.getJdbcTypeCount() );
|
||||
selectableMappings.forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
|
||||
sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
tableReference,
|
||||
selection.getSelectionExpression()
|
||||
),
|
||||
s ->
|
||||
new ColumnReference(
|
||||
identificationVariable,
|
||||
selection,
|
||||
creationState.getSqlAstCreationState()
|
||||
.getCreationContext()
|
||||
.getSessionFactory()
|
||||
)
|
||||
),
|
||||
selection.getJdbcMapping().getJavaTypeDescriptor(),
|
||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
final NavigablePath fkNavigablePath = navigablePath.append( getPartName() );
|
||||
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
|
||||
fkNavigablePath,
|
||||
np -> {
|
||||
final TableGroupJoin tableGroupJoin = modelPart.createTableGroupJoin(
|
||||
fkNavigablePath,
|
||||
tableGroup,
|
||||
null,
|
||||
SqlAstJoinType.INNER,
|
||||
LockMode.NONE,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
sqlSelections.add( sqlSelection );
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
return new EmbeddableForeignKeyResultImpl<>(
|
||||
sqlSelections,
|
||||
collectionPath,
|
||||
mappingType,
|
||||
navigablePath,
|
||||
modelPart,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
|
@ -344,19 +372,24 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
return associationKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getKeyPart() {
|
||||
return keyMappingType.getEmbeddableTypeDescriptor().getEmbeddedValueMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
throw new HibernateException( "Unexpected call to SimpleForeignKeyDescriptor#getPartMappingType" );
|
||||
return targetMappingType.getPartMappingType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor<?> getJavaTypeDescriptor() {
|
||||
return mappingType.getJavaTypeDescriptor();
|
||||
return targetMappingType.getJavaTypeDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigableRole getNavigableRole() {
|
||||
throw new UnsupportedOperationException();
|
||||
return targetMappingType.getNavigableRole();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -365,41 +398,26 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
//noinspection unchecked
|
||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference( keyTable );
|
||||
final String identificationVariable = tableReference.getIdentificationVariable();
|
||||
final int size = keySelectableMappings.getJdbcTypeCount();
|
||||
final List<SqlSelection> sqlSelections = new ArrayList<>( size );
|
||||
keySelectableMappings.forEachSelectable(
|
||||
(columnIndex, selection) -> {
|
||||
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
|
||||
sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey(
|
||||
tableReference,
|
||||
selection.getSelectionExpression()
|
||||
),
|
||||
s ->
|
||||
new ColumnReference(
|
||||
identificationVariable,
|
||||
selection,
|
||||
creationState.getSqlAstCreationState()
|
||||
.getCreationContext()
|
||||
.getSessionFactory()
|
||||
)
|
||||
),
|
||||
selection.getJdbcMapping().getJavaTypeDescriptor(),
|
||||
sqlAstCreationState.getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
final NavigablePath fkNavigablePath = navigablePath.append( getPartName() );
|
||||
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
|
||||
fkNavigablePath,
|
||||
np -> {
|
||||
final TableGroupJoin tableGroupJoin = keyMappingType.createTableGroupJoin(
|
||||
fkNavigablePath,
|
||||
tableGroup,
|
||||
null,
|
||||
null,
|
||||
LockMode.NONE,
|
||||
creationState.getSqlAstCreationState()
|
||||
);
|
||||
sqlSelections.add( sqlSelection );
|
||||
return tableGroupJoin.getJoinedGroup();
|
||||
}
|
||||
|
||||
);
|
||||
|
||||
return new EmbeddableForeignKeyResultImpl<>(
|
||||
sqlSelections,
|
||||
navigablePath,
|
||||
mappingType,
|
||||
keyMappingType,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
|
@ -419,8 +437,8 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
@Override
|
||||
public Object getAssociationKeyFromTarget(Object targetObject, SharedSessionContractImplementor session) {
|
||||
// If the mapping type has an identifier type, that identifier is the key
|
||||
if ( mappingType instanceof SingleAttributeIdentifierMapping ) {
|
||||
return ( (SingleAttributeIdentifierMapping) mappingType ).getIdentifier( targetObject, session );
|
||||
if ( targetMappingType instanceof SingleAttributeIdentifierMapping ) {
|
||||
return ( (SingleAttributeIdentifierMapping) targetMappingType ).getIdentifier( targetObject, session );
|
||||
}
|
||||
// Otherwise this is a key based on the target object i.e. without id-class
|
||||
return targetObject;
|
||||
|
@ -428,12 +446,12 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
|
||||
@Override
|
||||
public EntityMappingType findContainingEntityMapping() {
|
||||
throw new UnsupportedOperationException();
|
||||
return targetMappingType.findContainingEntityMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
|
||||
return mappingType.forEachJdbcType( offset, action );
|
||||
return targetMappingType.forEachJdbcType( offset, action );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -443,11 +461,11 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
int offset,
|
||||
JdbcValuesConsumer valuesConsumer,
|
||||
SharedSessionContractImplementor session) {
|
||||
return mappingType.forEachDisassembledJdbcValue( value, clause, offset, valuesConsumer, session );
|
||||
return targetMappingType.forEachDisassembledJdbcValue( value, clause, offset, valuesConsumer, session );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object disassemble(Object value, SharedSessionContractImplementor session) {
|
||||
return mappingType.disassemble( value, session );
|
||||
return targetMappingType.disassemble( value, session );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,9 @@ package org.hibernate.metamodel.mapping.internal;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
|
@ -17,17 +19,16 @@ import org.hibernate.engine.FetchTiming;
|
|||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.mapping.IndexedConsumer;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingModelExpressable;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableMappings;
|
||||
import org.hibernate.metamodel.mapping.ValueMapping;
|
||||
import org.hibernate.metamodel.model.domain.NavigableRole;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
|
@ -57,8 +58,8 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicValuedModelPart, FetchOptions {
|
||||
private final SideModelPart keySide;
|
||||
private final SideModelPart targetSide;
|
||||
private final BasicValuedModelPart keySide;
|
||||
private final BasicValuedModelPart targetSide;
|
||||
|
||||
private final boolean refersToPrimaryKey;
|
||||
|
||||
|
@ -68,45 +69,57 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
|
||||
public SimpleForeignKeyDescriptor(
|
||||
SelectableMapping keySelectableMapping,
|
||||
SelectableMapping targetSelectableMapping,
|
||||
Function<Object,Object> disassemblyValueExtractor,
|
||||
BasicValuedModelPart targetModelPart,
|
||||
Function<Object, Object> disassemblyValueExtractor,
|
||||
boolean refersToPrimaryKey) {
|
||||
assert keySelectableMapping != null;
|
||||
assert targetSelectableMapping != null;
|
||||
assert targetModelPart != null;
|
||||
assert disassemblyValueExtractor != null;
|
||||
|
||||
this.keySide = new SideModelPart( keySelectableMapping );
|
||||
this.targetSide = new SideModelPart( targetSelectableMapping );
|
||||
this.keySide = BasicValuedSingularAttributeMapping.withSelectableMapping( targetModelPart, keySelectableMapping );
|
||||
this.targetSide = targetModelPart;
|
||||
this.disassemblyValueExtractor = disassemblyValueExtractor;
|
||||
this.refersToPrimaryKey = refersToPrimaryKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getKeyTable() {
|
||||
return keySide.selectableMapping.getContainingTableExpression();
|
||||
return keySide.getContainingTableExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTargetTable() {
|
||||
return targetSide.selectableMapping.getContainingTableExpression();
|
||||
return targetSide.getContainingTableExpression();
|
||||
}
|
||||
|
||||
public SideModelPart getKeySide() {
|
||||
public BasicValuedModelPart getKeySide() {
|
||||
return keySide;
|
||||
}
|
||||
|
||||
public SideModelPart getTargetSide() {
|
||||
public BasicValuedModelPart getTargetSide() {
|
||||
return targetSide;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForeignKeyDescriptor withKeySelectionMapping(
|
||||
IntFunction<SelectableMapping> selectableMappingAccess,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
return new SimpleForeignKeyDescriptor(
|
||||
selectableMappingAccess.apply( 0 ),
|
||||
targetSide,
|
||||
disassemblyValueExtractor,
|
||||
refersToPrimaryKey
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> createCollectionFetchDomainResult(
|
||||
NavigablePath collectionPath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( targetSide.selectableMapping.getContainingTableExpression()
|
||||
.equals( keySide.selectableMapping.getContainingTableExpression() ) ) {
|
||||
return createDomainResult( tableGroup, targetSide.selectableMapping, creationState );
|
||||
if ( targetSide.getContainingTableExpression()
|
||||
.equals( keySide.getContainingTableExpression() ) ) {
|
||||
return createDomainResult( collectionPath, tableGroup, targetSide, creationState );
|
||||
}
|
||||
return createDomainResult( collectionPath, tableGroup, creationState );
|
||||
}
|
||||
|
@ -116,7 +129,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
return createDomainResult( tableGroup, keySide.selectableMapping, creationState );
|
||||
return createDomainResult( navigablePath, tableGroup, keySide, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -126,9 +139,9 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
boolean isKeyReferringSide,
|
||||
DomainResultCreationState creationState) {
|
||||
if ( isKeyReferringSide ) {
|
||||
return createDomainResult( tableGroup, keySide.selectableMapping, creationState );
|
||||
return createDomainResult( navigablePath, tableGroup, keySide, creationState );
|
||||
}
|
||||
return createDomainResult( tableGroup, targetSide.selectableMapping, creationState );
|
||||
return createDomainResult( navigablePath, tableGroup, targetSide, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -137,10 +150,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return createDomainResult( tableGroup, keySide.selectableMapping, creationState );
|
||||
return createDomainResult( navigablePath, tableGroup, keySide, creationState );
|
||||
}
|
||||
|
||||
private <T> DomainResult<T> createDomainResult(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
SelectableMapping selectableMapping,
|
||||
DomainResultCreationState creationState) {
|
||||
|
@ -180,17 +194,17 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
SqlAstJoinType sqlAstJoinType,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
if ( lhs.getTableReference( keySide.selectableMapping.getContainingTableExpression() ) != null ) {
|
||||
if ( lhs.getTableReference( keySide.getContainingTableExpression() ) != null ) {
|
||||
return new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
lhs,
|
||||
keySide.selectableMapping,
|
||||
keySide,
|
||||
creationContext.getSessionFactory()
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
new ColumnReference(
|
||||
rhs,
|
||||
targetSide.selectableMapping,
|
||||
targetSide,
|
||||
creationContext.getSessionFactory()
|
||||
)
|
||||
);
|
||||
|
@ -199,13 +213,13 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
return new ComparisonPredicate(
|
||||
new ColumnReference(
|
||||
lhs,
|
||||
targetSide.selectableMapping,
|
||||
targetSide,
|
||||
creationContext.getSessionFactory()
|
||||
),
|
||||
ComparisonOperator.EQUAL,
|
||||
new ColumnReference(
|
||||
rhs,
|
||||
keySide.selectableMapping,
|
||||
keySide,
|
||||
creationContext.getSessionFactory()
|
||||
)
|
||||
);
|
||||
|
@ -221,22 +235,22 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
SqlAstCreationContext creationContext) {
|
||||
TableReference lhsTableReference;
|
||||
TableReference rhsTableKeyReference;
|
||||
if ( targetSide.selectableMapping.getContainingTableExpression().equals( keySide.selectableMapping.getContainingTableExpression() ) ) {
|
||||
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keySide.selectableMapping.getContainingTableExpression() );
|
||||
if ( targetSide.getContainingTableExpression().equals( keySide.getContainingTableExpression() ) ) {
|
||||
lhsTableReference = getTableReferenceWhenTargetEqualsKey( lhs, tableGroup, keySide.getContainingTableExpression() );
|
||||
|
||||
rhsTableKeyReference = getTableReference(
|
||||
lhs,
|
||||
tableGroup,
|
||||
targetSide.selectableMapping.getContainingTableExpression()
|
||||
targetSide.getContainingTableExpression()
|
||||
);
|
||||
}
|
||||
else {
|
||||
lhsTableReference = getTableReference( lhs, tableGroup, keySide.selectableMapping.getContainingTableExpression() );
|
||||
lhsTableReference = getTableReference( lhs, tableGroup, keySide.getContainingTableExpression() );
|
||||
|
||||
rhsTableKeyReference = getTableReference(
|
||||
lhs,
|
||||
tableGroup,
|
||||
targetSide.selectableMapping.getContainingTableExpression()
|
||||
targetSide.getContainingTableExpression()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -282,6 +296,16 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
throw new IllegalStateException( "Could not resolve binding for table `" + table + "`" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getKeyPart() {
|
||||
return keySide;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getPartMappingType() {
|
||||
return targetSide.getMappedType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JavaTypeDescriptor<?> getJavaTypeDescriptor() {
|
||||
return targetSide.getJdbcMapping().getJavaTypeDescriptor();
|
||||
|
@ -289,12 +313,12 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
|
||||
@Override
|
||||
public NavigableRole getNavigableRole() {
|
||||
throw new UnsupportedOperationException();
|
||||
return targetSide.getNavigableRole();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType findContainingEntityMapping() {
|
||||
throw new UnsupportedOperationException();
|
||||
return targetSide.findContainingEntityMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -326,26 +350,26 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
|
||||
@Override
|
||||
public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) {
|
||||
valueConsumer.consume( domainValue, keySide.selectableMapping );
|
||||
valueConsumer.consume( domainValue, keySide );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visitKeySelectables(int offset, SelectableConsumer consumer) {
|
||||
consumer.accept( offset, keySide.selectableMapping );
|
||||
consumer.accept( offset, keySide );
|
||||
return getJdbcTypeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int visitTargetSelectables(int offset, SelectableConsumer consumer) {
|
||||
consumer.accept( offset, targetSide.selectableMapping );
|
||||
consumer.accept( offset, targetSide );
|
||||
return getJdbcTypeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssociationKey getAssociationKey() {
|
||||
if ( associationKey == null ) {
|
||||
final List<String> associationKeyColumns = Collections.singletonList( keySide.selectableMapping.getSelectionExpression() );
|
||||
associationKey = new AssociationKey( keySide.selectableMapping.getContainingTableExpression(), associationKeyColumns );
|
||||
final List<String> associationKeyColumns = Collections.singletonList( keySide.getSelectionExpression() );
|
||||
associationKey = new AssociationKey( keySide.getContainingTableExpression(), associationKeyColumns );
|
||||
}
|
||||
return associationKey;
|
||||
}
|
||||
|
@ -375,27 +399,27 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
|
||||
@Override
|
||||
public String getContainingTableExpression() {
|
||||
return keySide.selectableMapping.getContainingTableExpression();
|
||||
return keySide.getContainingTableExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSelectionExpression() {
|
||||
return keySide.selectableMapping.getSelectionExpression();
|
||||
return keySide.getSelectionExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFormula() {
|
||||
return keySide.selectableMapping.isFormula();
|
||||
return keySide.isFormula();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomReadExpression() {
|
||||
return keySide.selectableMapping.getCustomReadExpression();
|
||||
return keySide.getCustomReadExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCustomWriteExpression() {
|
||||
return keySide.selectableMapping.getCustomWriteExpression();
|
||||
return keySide.getCustomWriteExpression();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -444,70 +468,10 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
public String toString() {
|
||||
return String.format(
|
||||
"SimpleForeignKeyDescriptor : %s.%s -> %s.%s",
|
||||
keySide.selectableMapping.getContainingTableExpression(),
|
||||
keySide.selectableMapping.getSelectionExpression(),
|
||||
targetSide.selectableMapping.getContainingTableExpression(),
|
||||
targetSide.selectableMapping.getSelectionExpression()
|
||||
keySide.getContainingTableExpression(),
|
||||
keySide.getSelectionExpression(),
|
||||
targetSide.getContainingTableExpression(),
|
||||
targetSide.getSelectionExpression()
|
||||
);
|
||||
}
|
||||
|
||||
private interface KeySideModelPart extends MappingModelExpressable, DomainResultProducer, SelectableMappings {
|
||||
@Override
|
||||
default int getJdbcTypeCount() {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
|
||||
@Override
|
||||
default List<JdbcMapping> getJdbcMappings() {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
}
|
||||
|
||||
public static class SideModelPart implements BasicValuedMapping, KeySideModelPart {
|
||||
private final SelectableMapping selectableMapping;
|
||||
private final List<JdbcMapping> jdbcMappings;
|
||||
|
||||
public SideModelPart(SelectableMapping selectableMapping) {
|
||||
assert selectableMapping != null;
|
||||
this.selectableMapping = selectableMapping;
|
||||
|
||||
this.jdbcMappings = Collections.singletonList( getJdbcMapping() );
|
||||
}
|
||||
|
||||
public SelectableMapping getSelectableMapping() {
|
||||
return selectableMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getJdbcTypeCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JdbcMapping> getJdbcMappings() {
|
||||
return jdbcMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcMapping getJdbcMapping() {
|
||||
return selectableMapping.getJdbcMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getMappedType() {
|
||||
return getJdbcMapping();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelectableMapping getSelectable(int columnIndex) {
|
||||
assert columnIndex == 0;
|
||||
return selectableMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int forEachSelectable(int offset, SelectableConsumer consumer) {
|
||||
consumer.accept( offset, selectableMapping );
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,12 +16,14 @@ import org.hibernate.mapping.ManyToOne;
|
|||
import org.hibernate.mapping.OneToOne;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ManagedMappingType;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
|
@ -48,6 +50,7 @@ import org.hibernate.sql.ast.tree.from.TableReference;
|
|||
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.FetchOptions;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable;
|
||||
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
||||
|
@ -84,7 +87,7 @@ public class ToOneAttributeMapping
|
|||
private final String referencedPropertyName;
|
||||
|
||||
private final Cardinality cardinality;
|
||||
private String bidirectionalAttributeName;
|
||||
private final String bidirectionalAttributeName;
|
||||
|
||||
private ForeignKeyDescriptor foreignKeyDescriptor;
|
||||
private String identifyingColumnsTableExpression;
|
||||
|
@ -122,6 +125,7 @@ public class ToOneAttributeMapping
|
|||
else {
|
||||
cardinality = Cardinality.MANY_TO_ONE;
|
||||
}
|
||||
this.bidirectionalAttributeName = null;
|
||||
}
|
||||
else {
|
||||
assert bootValue instanceof OneToOne;
|
||||
|
@ -171,22 +175,49 @@ public class ToOneAttributeMapping
|
|||
so in order to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value.
|
||||
*/
|
||||
// todo (6.0): find a better solution for the embeddable part name not in the NavigablePath
|
||||
bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
||||
String bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
||||
( (OneToOne) bootValue ).getMappedByProperty(),
|
||||
'.'
|
||||
);
|
||||
|
||||
if ( bidirectionalAttributeName == null ) {
|
||||
bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
||||
this.bidirectionalAttributeName = StringHelper.subStringNullIfEmpty(
|
||||
bootValue.getReferencedPropertyName(),
|
||||
'.'
|
||||
);
|
||||
}
|
||||
else {
|
||||
this.bidirectionalAttributeName = bidirectionalAttributeName;
|
||||
}
|
||||
}
|
||||
|
||||
this.navigableRole = navigableRole;
|
||||
}
|
||||
|
||||
private ToOneAttributeMapping(ToOneAttributeMapping original) {
|
||||
super(
|
||||
original.getAttributeName(),
|
||||
original.getStateArrayPosition(),
|
||||
original.getAttributeMetadataAccess(),
|
||||
original,
|
||||
original.getDeclaringType(),
|
||||
original.getPropertyAccess()
|
||||
);
|
||||
this.navigableRole = original.navigableRole;
|
||||
this.sqlAliasStem = original.sqlAliasStem;
|
||||
this.isNullable = original.isNullable;
|
||||
this.unwrapProxy = original.unwrapProxy;
|
||||
this.entityMappingType = original.entityMappingType;
|
||||
this.referencedPropertyName = original.referencedPropertyName;
|
||||
this.cardinality = original.cardinality;
|
||||
this.bidirectionalAttributeName = original.bidirectionalAttributeName;
|
||||
}
|
||||
|
||||
public ToOneAttributeMapping copy() {
|
||||
return new ToOneAttributeMapping( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
|
||||
isKeyReferringSide = foreignKeyDescriptor.getAssociationKey().getTable().equals( identifyingColumnsTableExpression );
|
||||
assert identifyingColumnsTableExpression != null;
|
||||
|
@ -197,6 +228,7 @@ public class ToOneAttributeMapping
|
|||
identifyingColumnsTableExpression = tableExpression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ForeignKeyDescriptor getForeignKeyDescriptor() {
|
||||
return this.foreignKeyDescriptor;
|
||||
}
|
||||
|
@ -205,6 +237,10 @@ public class ToOneAttributeMapping
|
|||
return referencedPropertyName;
|
||||
}
|
||||
|
||||
public Cardinality getCardinality() {
|
||||
return cardinality;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityMappingType getMappedType() {
|
||||
return getEntityMappingType();
|
||||
|
@ -230,6 +266,35 @@ public class ToOneAttributeMapping
|
|||
if ( creationState.isAssociationKeyVisited( associationKey ) ) {
|
||||
NavigablePath parentNavigablePath = fetchablePath.getParent();
|
||||
assert parentNavigablePath.equals( fetchParent.getNavigablePath() );
|
||||
// The parent navigable path is {fk} if we are creating the domain result for the foreign key for a circular fetch
|
||||
// In the following example, we create a circular fetch for the composite `Card.field.{id}.card.field`
|
||||
// While creating the domain result for the foreign key of `Card#field`, we run into this condition
|
||||
// We know that `Card#field` will be delayed because `EmbeddableForeignKeyResultImpl` enforces that
|
||||
// so we can safely return null to avoid a stack overflow
|
||||
/*
|
||||
@Entity
|
||||
public class Card {
|
||||
@Id
|
||||
private String id;
|
||||
@ManyToOne
|
||||
private CardField field;
|
||||
}
|
||||
@Entity
|
||||
public class CardField {
|
||||
@EmbeddedId
|
||||
private PrimaryKey primaryKey;
|
||||
}
|
||||
@Embeddable
|
||||
public class PrimaryKey {
|
||||
@ManyToOne(optional = false)
|
||||
private Card card;
|
||||
@ManyToOne(optional = false)
|
||||
private Key key;
|
||||
}
|
||||
*/
|
||||
if ( parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
ModelPart modelPart = creationState.resolveModelPart( parentNavigablePath );
|
||||
if ( modelPart instanceof EmbeddedIdentifierMappingImpl ) {
|
||||
|
@ -407,6 +472,9 @@ public class ToOneAttributeMapping
|
|||
fetchParent.getNavigablePath()
|
||||
);
|
||||
|
||||
final NavigablePath parentNavigablePath = fetchablePath.getParent();
|
||||
assert parentNavigablePath.equals( fetchParent.getNavigablePath() );
|
||||
|
||||
if ( fetchTiming == FetchTiming.IMMEDIATE && selected ) {
|
||||
if ( fetchParent instanceof EntityResultJoinedSubclassImpl &&
|
||||
( (EntityPersister) fetchParent.getReferencedModePart() ).findDeclaredAttributeMapping( getPartName() ) == null ) {
|
||||
|
@ -471,12 +539,11 @@ public class ToOneAttributeMapping
|
|||
selectByUniqueKey = false;
|
||||
}
|
||||
else {
|
||||
// case 1.1
|
||||
keyResult = foreignKeyDescriptor.createDomainResult( fetchablePath, parentTableGroup, isKeyReferringSide, creationState );
|
||||
// case 1.1
|
||||
selectByUniqueKey = true;
|
||||
}
|
||||
|
||||
assert !selected;
|
||||
if ( fetchTiming == FetchTiming.IMMEDIATE ) {
|
||||
return new EntityFetchSelectImpl(
|
||||
fetchParent,
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.query.NavigablePath;
|
|||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
|
@ -57,19 +58,17 @@ public class ColumnReference implements OrderingExpression, SequencePart {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void apply(
|
||||
public Expression resolve(
|
||||
QuerySpec ast,
|
||||
TableGroup tableGroup,
|
||||
String collation,
|
||||
String modelPartName,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState) {
|
||||
TableReference tableReference;
|
||||
|
||||
tableReference = getTableReference( tableGroup );
|
||||
|
||||
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlExpressionResolver();
|
||||
final Expression expression = sqlExpressionResolver.resolveSqlExpression(
|
||||
return sqlExpressionResolver.resolveSqlExpression(
|
||||
SqlExpressionResolver.createColumnReferenceKey( tableReference, columnExpression ),
|
||||
sqlAstProcessingState -> new org.hibernate.sql.ast.tree.expression.ColumnReference(
|
||||
tableReference,
|
||||
|
@ -83,6 +82,17 @@ public class ColumnReference implements OrderingExpression, SequencePart {
|
|||
creationState.getCreationContext().getSessionFactory()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(
|
||||
QuerySpec ast,
|
||||
TableGroup tableGroup,
|
||||
String collation,
|
||||
String modelPartName,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState) {
|
||||
final Expression expression = resolve( ast, tableGroup, modelPartName, creationState );
|
||||
// It makes no sense to order by an expression multiple times
|
||||
// SQL Server even reports a query error in this case
|
||||
if ( ast.hasSortSpecifications() ) {
|
||||
|
|
|
@ -11,17 +11,28 @@ import java.util.Collections;
|
|||
import java.util.List;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.AbstractDomainPath;
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.query.sqm.function.FunctionRenderingSupport;
|
||||
import org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression;
|
||||
import org.hibernate.sql.ast.SqlAstTranslator;
|
||||
import org.hibernate.sql.ast.spi.SqlAppender;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SortSpecification;
|
||||
|
||||
/**
|
||||
* Represents a function used in an order-by fragment
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class FunctionExpression implements OrderingExpression {
|
||||
public class FunctionExpression implements OrderingExpression, FunctionRenderingSupport {
|
||||
private final String name;
|
||||
private final List<OrderingExpression> arguments;
|
||||
|
||||
|
@ -44,6 +55,42 @@ public class FunctionExpression implements OrderingExpression {
|
|||
arguments.add( argument );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SelfRenderingFunctionSqlAstExpression resolve(
|
||||
QuerySpec ast,
|
||||
TableGroup tableGroup,
|
||||
String modelPartName,
|
||||
SqlAstCreationState creationState) {
|
||||
|
||||
final int size = arguments.size();
|
||||
final List<SqlAstNode> args = new ArrayList<>( size );
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final OrderingExpression orderingExpression = arguments.get( i );
|
||||
final String subModelPartName;
|
||||
if ( orderingExpression instanceof DomainPath ) {
|
||||
final String partName = ( (DomainPath) orderingExpression ).getNavigablePath().getUnaliasedLocalName();
|
||||
if ( CollectionPart.Nature.ELEMENT.getName().equals( partName ) ) {
|
||||
subModelPartName = AbstractDomainPath.ELEMENT_TOKEN;
|
||||
}
|
||||
else {
|
||||
subModelPartName = partName;
|
||||
}
|
||||
}
|
||||
else {
|
||||
subModelPartName = null;
|
||||
}
|
||||
args.add( orderingExpression.resolve( ast, tableGroup, subModelPartName, creationState ) );
|
||||
}
|
||||
|
||||
return new SelfRenderingFunctionSqlAstExpression(
|
||||
name,
|
||||
this,
|
||||
args,
|
||||
null,
|
||||
tableGroup.getModelPart().findSubPart( modelPartName, null )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(
|
||||
QuerySpec ast,
|
||||
|
@ -52,6 +99,21 @@ public class FunctionExpression implements OrderingExpression {
|
|||
String modelPartName,
|
||||
SortOrder sortOrder,
|
||||
SqlAstCreationState creationState) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
final SelfRenderingFunctionSqlAstExpression expression = resolve( ast, tableGroup, modelPartName, creationState );
|
||||
ast.addSortSpecification( new SortSpecification( expression, collation, sortOrder ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(SqlAppender sqlAppender, List<SqlAstNode> sqlAstArguments, SqlAstTranslator<?> walker) {
|
||||
sqlAppender.appendSql( name );
|
||||
sqlAppender.appendSql( '(' );
|
||||
if ( !sqlAstArguments.isEmpty() ) {
|
||||
sqlAstArguments.get( 0 ).accept( walker );
|
||||
for ( int i = 1; i < sqlAstArguments.size(); i++ ) {
|
||||
sqlAppender.appendSql( ", " );
|
||||
sqlAstArguments.get( i ).accept( walker );
|
||||
}
|
||||
}
|
||||
sqlAppender.appendSql( ')' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.metamodel.mapping.ordering.ast;
|
|||
|
||||
import org.hibernate.query.SortOrder;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||
import org.hibernate.sql.ast.tree.SqlAstNode;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
|
||||
|
@ -17,6 +18,9 @@ import org.hibernate.sql.ast.tree.select.QuerySpec;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface OrderingExpression extends Node {
|
||||
|
||||
SqlAstNode resolve(QuerySpec ast, TableGroup tableGroup, String modelPartName, SqlAstCreationState creationState);
|
||||
|
||||
/**
|
||||
* Apply the SQL AST sort-specifications associated with this ordering-expression
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* 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.procedure.internal;
|
||||
|
||||
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.ResultBuilder;
|
||||
import org.hibernate.query.results.ResultBuilderBasicValued;
|
||||
import org.hibernate.query.results.complete.EntityResultImpl;
|
||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderBasic;
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class EntityDomainResultBuilder<T> implements ResultBuilder {
|
||||
|
||||
private final NavigablePath navigablePath;
|
||||
private final EntityMappingType entityDescriptor;
|
||||
private final ResultBuilderBasicValued discriminatorResultBuilder;
|
||||
|
||||
public EntityDomainResultBuilder(EntityMappingType entityDescriptor) {
|
||||
this.entityDescriptor = entityDescriptor;
|
||||
this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() );
|
||||
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
|
||||
if ( discriminatorMapping == null ) {
|
||||
this.discriminatorResultBuilder = null;
|
||||
}
|
||||
else {
|
||||
this.discriminatorResultBuilder = new ImplicitModelPartResultBuilderBasic(
|
||||
navigablePath,
|
||||
discriminatorMapping
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityResult buildResult(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
int resultPosition,
|
||||
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
|
||||
DomainResultCreationState domainResultCreationState) {
|
||||
final BasicResult<?> discriminatorResult;
|
||||
if ( discriminatorResultBuilder == null ) {
|
||||
discriminatorResult = null;
|
||||
}
|
||||
else {
|
||||
discriminatorResult = discriminatorResultBuilder.buildResult(
|
||||
jdbcResultsMetadata,
|
||||
resultPosition,
|
||||
legacyFetchResolver,
|
||||
domainResultCreationState
|
||||
);
|
||||
}
|
||||
|
||||
return new EntityResultImpl(
|
||||
navigablePath,
|
||||
entityDescriptor,
|
||||
null,
|
||||
LockMode.NONE,
|
||||
discriminatorResult,
|
||||
domainResultCreationState
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* 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.procedure.internal;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.hibernate.query.results.ResultBuilder;
|
||||
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.basic.BasicResult;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ScalarDomainResultBuilder<T> implements ResultBuilder {
|
||||
private final JavaTypeDescriptor<T> typeDescriptor;
|
||||
|
||||
public ScalarDomainResultBuilder(JavaTypeDescriptor<T> typeDescriptor) {
|
||||
this.typeDescriptor = typeDescriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<T> buildResult(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
int resultPosition,
|
||||
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
|
||||
DomainResultCreationState domainResultCreationState) {
|
||||
return new BasicResult<>( resultPosition, null, typeDescriptor );
|
||||
}
|
||||
}
|
|
@ -1,33 +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.procedure.internal;
|
||||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.query.sqm.SqmExpressable;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ScalarDomainResultProducer<T> implements DomainResultProducer<T> {
|
||||
private final SqmExpressable<T> expressableType;
|
||||
|
||||
public ScalarDomainResultProducer(SqmExpressable<T> expressableType) {
|
||||
this.expressableType = expressableType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<T> createDomainResult(
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
// //noinspection unchecked
|
||||
// return new ScalarDomainResultImpl( resultVariable, expressableType.getExpressableJavaTypeDescriptor() );
|
||||
}
|
||||
}
|
|
@ -10,10 +10,15 @@ import java.util.function.Consumer;
|
|||
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.metamodel.MappingMetamodel;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
|
@ -70,26 +75,23 @@ public class Util {
|
|||
ResultSetMapping resultSetMapping,
|
||||
Consumer<String> querySpaceConsumer,
|
||||
ResultSetMappingResolutionContext context) {
|
||||
throw new NotYetImplementedFor6Exception( Util.class );
|
||||
final MappingMetamodel domainModel = context.getSessionFactory().getDomainModel();
|
||||
final TypeConfiguration typeConfiguration = domainModel.getTypeConfiguration();
|
||||
|
||||
// final DomainMetamodel domainModel = sessionFactory.getDomainModel();
|
||||
// final TypeConfiguration typeConfiguration = domainModel.getTypeConfiguration();
|
||||
//
|
||||
// for ( Class resultSetMappingClass : resultSetMappingClasses ) {
|
||||
// final BasicType basicType = typeConfiguration.getBasicTypeForJavaType( resultSetMappingClass );
|
||||
// if ( basicType != null ) {
|
||||
// //noinspection unchecked
|
||||
// resultProducerConsumer.accept( new ScalarDomainResultProducer<>( basicType ) );
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( resultSetMappingClass );
|
||||
// if ( entityDescriptor != null ) {
|
||||
// resultProducerConsumer.accept( new Entity );
|
||||
// for ( String querySpace : entityDescriptor.getSynchronizedQuerySpaces() ) {
|
||||
// querySpaceConsumer.accept( querySpace );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
for ( Class<?> resultSetMappingClass : resultSetMappingClasses ) {
|
||||
final JavaTypeDescriptor<?> basicType = typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( resultSetMappingClass );
|
||||
if ( basicType != null ) {
|
||||
resultSetMapping.addResultBuilder( new ScalarDomainResultBuilder<>( basicType ) );
|
||||
continue;
|
||||
}
|
||||
|
||||
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor( resultSetMappingClass );
|
||||
if ( entityDescriptor != null ) {
|
||||
resultSetMapping.addResultBuilder( new EntityDomainResultBuilder( entityDescriptor ) );
|
||||
for ( String querySpace : entityDescriptor.getSynchronizedQuerySpaces() ) {
|
||||
querySpaceConsumer.accept( querySpace );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,9 @@ import org.hibernate.metamodel.RuntimeMetamodels;
|
|||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
|
||||
|
@ -33,6 +35,8 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
|||
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.ImplicitFetchBuilderEntity;
|
||||
import org.hibernate.query.results.implicit.ImplicitFetchBuilderPlural;
|
||||
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderEntity;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
|
@ -258,9 +262,13 @@ public class Builders {
|
|||
return new ImplicitFetchBuilderEmbeddable( fetchPath, embeddableValuedFetchable, creationState );
|
||||
}
|
||||
|
||||
if ( fetchable instanceof EntityValuedFetchable ) {
|
||||
final EntityValuedFetchable entityValuedFetchable = (EntityValuedFetchable) fetchable;
|
||||
throw new NotYetImplementedFor6Exception( "Support for implicit entity-valued fetches is not yet implemented" );
|
||||
if ( fetchable instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) fetchable;
|
||||
return new ImplicitFetchBuilderEntity( fetchPath, toOneAttributeMapping, creationState );
|
||||
}
|
||||
|
||||
if ( fetchable instanceof PluralAttributeMapping ) {
|
||||
return new ImplicitFetchBuilderPlural( fetchPath, (PluralAttributeMapping) fetchable, creationState );
|
||||
}
|
||||
|
||||
throw new UnsupportedOperationException();
|
||||
|
|
|
@ -14,13 +14,17 @@ import java.util.function.Function;
|
|||
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
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.Association;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
|
||||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||
|
@ -43,8 +47,6 @@ 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.graph.embeddable.EmbeddableValuedFetchable;
|
||||
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;
|
||||
|
@ -317,8 +319,20 @@ public class DomainResultCreationStateImpl
|
|||
final NavigablePath relativePath = relativePathStack.isEmpty()
|
||||
? new NavigablePath( fetchableName )
|
||||
: relativePathStack.getCurrent().append( fetchableName );
|
||||
|
||||
relativePathStack.push( relativePath );
|
||||
// todo (6.0): figure out if we can somehow create the navigable paths in a better way
|
||||
if ( fetchable instanceof Association && fetchable.getMappedFetchOptions().getTiming() == FetchTiming.DELAYED ) {
|
||||
final Association association = (Association) fetchable;
|
||||
final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor();
|
||||
if ( foreignKeyDescriptor.getPartMappingType() instanceof EmbeddableMappingType ) {
|
||||
relativePathStack.push( relativePath.append( ( (EmbeddableMappingType) foreignKeyDescriptor.getPartMappingType() ).getPartName() ) );
|
||||
}
|
||||
else {
|
||||
relativePathStack.push( relativePath.append( foreignKeyDescriptor.getPartName() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
relativePathStack.push( relativePath );
|
||||
}
|
||||
try {
|
||||
final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack
|
||||
.getCurrent()
|
||||
|
|
|
@ -42,8 +42,8 @@ public class ImplicitAttributeFetchBuilder implements FetchBuilder, ImplicitFetc
|
|||
DomainResultCreationState domainResultCreationState) {
|
||||
assert fetchPath.equals( navigablePath );
|
||||
|
||||
return attributeMapping.generateFetch(
|
||||
parent,
|
||||
return parent.generateFetchableFetch(
|
||||
attributeMapping,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
|
|
|
@ -104,8 +104,8 @@ public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, Mode
|
|||
processingState -> new SqlSelectionImpl( valuesArrayPosition, referencedModelPart )
|
||||
);
|
||||
|
||||
return referencedModelPart.generateFetch(
|
||||
parent,
|
||||
return parent.generateFetchableFetch(
|
||||
referencedModelPart,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
|
|
|
@ -99,8 +99,8 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
|
|||
}
|
||||
);
|
||||
|
||||
final Fetch fetch = fetchable.generateFetch(
|
||||
parent,
|
||||
final Fetch fetch = parent.generateFetchableFetch(
|
||||
fetchable,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
|
@ -108,16 +108,16 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
|
|||
null,
|
||||
creationState
|
||||
);
|
||||
final FetchParent fetchParent = (FetchParent) fetch;
|
||||
fetchBuilders.forEach(
|
||||
(subFetchPath, fetchBuilder) -> fetchBuilder.buildFetch(
|
||||
fetchParent,
|
||||
subFetchPath,
|
||||
jdbcResultsMetadata,
|
||||
legacyFetchResolver,
|
||||
creationState
|
||||
)
|
||||
);
|
||||
// final FetchParent fetchParent = (FetchParent) fetch;
|
||||
// fetchBuilders.forEach(
|
||||
// (subFetchPath, fetchBuilder) -> fetchBuilder.buildFetch(
|
||||
// fetchParent,
|
||||
// subFetchPath,
|
||||
// jdbcResultsMetadata,
|
||||
// legacyFetchResolver,
|
||||
// creationState
|
||||
// )
|
||||
// );
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
* 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.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.results.Builders;
|
||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||
import org.hibernate.query.results.FetchBuilder;
|
||||
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.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
import static org.hibernate.query.results.ResultsHelper.impl;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
|
||||
private final NavigablePath fetchPath;
|
||||
private final ToOneAttributeMapping fetchable;
|
||||
private final Map<NavigablePath, FetchBuilder> fetchBuilders;
|
||||
|
||||
public ImplicitFetchBuilderEntity(
|
||||
NavigablePath fetchPath,
|
||||
ToOneAttributeMapping fetchable,
|
||||
DomainResultCreationState creationState) {
|
||||
this.fetchPath = fetchPath;
|
||||
this.fetchable = fetchable;
|
||||
final DomainResultCreationStateImpl creationStateImpl = impl( creationState );
|
||||
final NavigablePath relativePath = creationStateImpl.getCurrentRelativePath();
|
||||
final Function<String, FetchBuilder> fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver();
|
||||
ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor();
|
||||
final String associationKeyPropertyName;
|
||||
if ( fetchable.getReferencedPropertyName() == null ) {
|
||||
associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName();
|
||||
}
|
||||
else {
|
||||
associationKeyPropertyName = fetchable.getReferencedPropertyName();
|
||||
}
|
||||
final NavigablePath associationKeyFetchPath = relativePath.append( associationKeyPropertyName );
|
||||
final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver
|
||||
.apply( associationKeyFetchPath.getFullPath() );
|
||||
final Map<NavigablePath, FetchBuilder> fetchBuilders;
|
||||
if ( explicitAssociationKeyFetchBuilder == null ) {
|
||||
final MappingType partMappingType = foreignKeyDescriptor.getPartMappingType();
|
||||
if ( partMappingType instanceof EmbeddableMappingType ) {
|
||||
final EmbeddableMappingType embeddableValuedModelPart = (EmbeddableMappingType) partMappingType;
|
||||
fetchBuilders = new LinkedHashMap<>( embeddableValuedModelPart.getNumberOfFetchables() );
|
||||
embeddableValuedModelPart.visitFetchables(
|
||||
subFetchable -> {
|
||||
final NavigablePath subFetchPath = associationKeyFetchPath.append( subFetchable.getFetchableName() );
|
||||
final FetchBuilder explicitFetchBuilder = fetchBuilderResolver
|
||||
.apply( subFetchPath.getFullPath() );
|
||||
if ( explicitFetchBuilder == null ) {
|
||||
fetchBuilders.put(
|
||||
subFetchPath,
|
||||
Builders.implicitFetchBuilder( fetchPath, subFetchable, creationStateImpl )
|
||||
);
|
||||
}
|
||||
else {
|
||||
fetchBuilders.put( subFetchPath, explicitFetchBuilder );
|
||||
}
|
||||
},
|
||||
null
|
||||
);
|
||||
}
|
||||
else {
|
||||
fetchBuilders = Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
else {
|
||||
fetchBuilders = Collections.singletonMap( associationKeyFetchPath, explicitAssociationKeyFetchBuilder );
|
||||
}
|
||||
this.fetchBuilders = fetchBuilders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch buildFetch(
|
||||
FetchParent parent,
|
||||
NavigablePath fetchPath,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
|
||||
DomainResultCreationState creationState) {
|
||||
final Fetch fetch = parent.generateFetchableFetch(
|
||||
fetchable,
|
||||
fetchPath,
|
||||
FetchTiming.DELAYED,
|
||||
false,
|
||||
LockMode.READ,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
// final FetchParent fetchParent = (FetchParent) fetch;
|
||||
// fetchBuilders.forEach(
|
||||
// (subFetchPath, fetchBuilder) -> fetchBuilder.buildFetch(
|
||||
// fetchParent,
|
||||
// subFetchPath,
|
||||
// jdbcResultsMetadata,
|
||||
// legacyFetchResolver,
|
||||
// creationState
|
||||
// )
|
||||
// );
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ImplicitFetchBuilderEntity(" + fetchPath + ")";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* 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.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.results.DomainResultCreationStateImpl;
|
||||
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.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
import static org.hibernate.query.results.ResultsHelper.impl;
|
||||
|
||||
/**
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
public class ImplicitFetchBuilderPlural implements ImplicitFetchBuilder {
|
||||
private final NavigablePath fetchPath;
|
||||
private final PluralAttributeMapping fetchable;
|
||||
|
||||
public ImplicitFetchBuilderPlural(
|
||||
NavigablePath fetchPath,
|
||||
PluralAttributeMapping fetchable,
|
||||
DomainResultCreationState creationState) {
|
||||
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 Fetch fetch = parent.generateFetchableFetch(
|
||||
fetchable,
|
||||
fetchPath,
|
||||
FetchTiming.DELAYED,
|
||||
false,
|
||||
LockMode.READ,
|
||||
null,
|
||||
creationState
|
||||
);
|
||||
|
||||
return fetch;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ImplicitFetchBuilderPlural(" + fetchPath + ")";
|
||||
}
|
||||
}
|
|
@ -1558,45 +1558,49 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
);
|
||||
}
|
||||
|
||||
if ( domainResults != null ) {
|
||||
final Stack<SqlAstProcessingState> processingStateStack = getProcessingStateStack();
|
||||
final boolean collectDomainResults;
|
||||
if ( processingStateStack.depth() == 1) {
|
||||
collectDomainResults = true;
|
||||
}
|
||||
else {
|
||||
final SqlAstProcessingState current = processingStateStack.getCurrent();
|
||||
// Since we only want to create domain results for the first/left-most query spec within query groups,
|
||||
// we have to check if the current query spec is the left-most.
|
||||
// This is the case when all upper level in-flight query groups are still empty
|
||||
collectDomainResults = processingStateStack.findCurrentFirst(
|
||||
processingState -> {
|
||||
if ( !( processingState instanceof SqlAstQueryPartProcessingState ) ) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
if ( processingState == current ) {
|
||||
return null;
|
||||
}
|
||||
final QueryPart part = ( (SqlAstQueryPartProcessingState) processingState ).getInflightQueryPart();
|
||||
if ( part instanceof QueryGroup ) {
|
||||
if ( ( (QueryGroup) part ).getQueryParts().isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
final Stack<SqlAstProcessingState> processingStateStack = getProcessingStateStack();
|
||||
final boolean needsDomainResults = domainResults != null && currentClauseContributesToTopLevelSelectClause();
|
||||
final boolean collectDomainResults;
|
||||
if ( processingStateStack.depth() == 1) {
|
||||
collectDomainResults = needsDomainResults;
|
||||
}
|
||||
else {
|
||||
final SqlAstProcessingState current = processingStateStack.getCurrent();
|
||||
// Since we only want to create domain results for the first/left-most query spec within query groups,
|
||||
// we have to check if the current query spec is the left-most.
|
||||
// This is the case when all upper level in-flight query groups are still empty
|
||||
collectDomainResults = needsDomainResults && processingStateStack.findCurrentFirst(
|
||||
processingState -> {
|
||||
if ( !( processingState instanceof SqlAstQueryPartProcessingState ) ) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
) == null;
|
||||
}
|
||||
if ( collectDomainResults ) {
|
||||
resultProducers.forEach( (alias, r) -> domainResults.add( r.createDomainResult( alias, this ) ) );
|
||||
}
|
||||
else {
|
||||
resultProducers.forEach( (alias, r) -> r.applySqlSelections( this ) );
|
||||
}
|
||||
if ( processingState == current ) {
|
||||
return null;
|
||||
}
|
||||
final QueryPart part = ( (SqlAstQueryPartProcessingState) processingState ).getInflightQueryPart();
|
||||
if ( part instanceof QueryGroup ) {
|
||||
if ( ( (QueryGroup) part ).getQueryParts().isEmpty() ) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
) == null;
|
||||
}
|
||||
if ( collectDomainResults ) {
|
||||
resultProducers.forEach( (alias, r) -> domainResults.add( r.createDomainResult( alias, this ) ) );
|
||||
}
|
||||
else {
|
||||
resultProducers.forEach( (alias, r) -> r.applySqlSelections( this ) );
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean currentClauseContributesToTopLevelSelectClause() {
|
||||
// The current clause contributes to the top level select if the clause stack contains just SELECT
|
||||
return currentClauseStack.findCurrentFirst( clause -> clause == Clause.SELECT ? null : clause ) == null;
|
||||
}
|
||||
|
||||
protected Expression resolveGroupOrOrderByExpression(SqmExpression<?> groupByClauseExpression) {
|
||||
if ( groupByClauseExpression instanceof SqmAliasedNodeRef ) {
|
||||
final int aliasedNodeOrdinal = ( (SqmAliasedNodeRef) groupByClauseExpression ).getPosition();
|
||||
|
@ -4303,8 +4307,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
@Override
|
||||
public InSubQueryPredicate visitInSubQueryPredicate(SqmInSubQueryPredicate predicate) {
|
||||
return new InSubQueryPredicate(
|
||||
(Expression) predicate.getTestExpression().accept( this ),
|
||||
(QueryPart) predicate.getSubQueryExpression().accept( this ),
|
||||
visitWithInferredType( predicate.getTestExpression(), predicate.getSubQueryExpression() ),
|
||||
visitWithInferredType( predicate.getSubQueryExpression(), predicate.getTestExpression() ),
|
||||
predicate.isNegated()
|
||||
);
|
||||
}
|
||||
|
@ -4515,8 +4519,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
|
||||
try {
|
||||
final Fetch fetch = fetchable.generateFetch(
|
||||
fetchParent,
|
||||
final Fetch fetch = fetchParent.generateFetchableFetch(
|
||||
fetchable,
|
||||
fetchablePath,
|
||||
fetchTiming,
|
||||
joined,
|
||||
|
|
|
@ -45,7 +45,7 @@ public abstract class AbstractSqmPathInterpretation<T> implements SqmPathInterpr
|
|||
return mapping;
|
||||
}
|
||||
|
||||
protected TableGroup getTableGroup() {
|
||||
public TableGroup getTableGroup() {
|
||||
return tableGroup;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ public class BasicValuedPathInterpretation<T> extends AbstractSqmPathInterpretat
|
|||
SqmBasicValuedSimplePath<T> sqmPath,
|
||||
SqlAstCreationState sqlAstCreationState,
|
||||
SemanticQueryWalker sqmWalker) {
|
||||
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||
TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||
|
||||
final BasicValuedModelPart mapping = (BasicValuedModelPart) tableGroup.getModelPart().findSubPart(
|
||||
sqmPath.getReferencedPathSource().getPathName(),
|
||||
|
|
|
@ -34,7 +34,7 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
|
|||
SqmEmbeddedValuedSimplePath<T> sqmPath,
|
||||
SqmToSqlAstConverter converter,
|
||||
SemanticQueryWalker sqmWalker) {
|
||||
final TableGroup tableGroup = converter.getFromClauseAccess()
|
||||
TableGroup tableGroup = converter.getFromClauseAccess()
|
||||
.findTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||
|
||||
final EmbeddableValuedModelPart mapping = (EmbeddableValuedModelPart) tableGroup.getModelPart().findSubPart(
|
||||
|
|
|
@ -17,7 +17,6 @@ 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.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
|
||||
|
@ -153,6 +152,14 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
|
|||
? (SqlTuple) sqlExpression
|
||||
: null;
|
||||
}
|
||||
@Override
|
||||
public void applySqlSelections(DomainResultCreationState creationState) {
|
||||
creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
|
||||
sqlExpression,
|
||||
getExpressionType().getJavaTypeDescriptor(),
|
||||
creationState.getSqlAstCreationState().getCreationContext().getDomainModel().getTypeConfiguration()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityValuedModelPart getExpressionType() {
|
||||
|
|
|
@ -8,6 +8,8 @@ package org.hibernate.sql.results.graph;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.Association;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
|
@ -64,4 +66,23 @@ public interface FetchParent extends DomainResultGraphNode {
|
|||
List<Fetch> getFetches();
|
||||
|
||||
Fetch findFetch(Fetchable fetchable);
|
||||
|
||||
default Fetch generateFetchableFetch(
|
||||
Fetchable fetchable,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return fetchable.generateFetch(
|
||||
this,
|
||||
fetchablePath,
|
||||
fetchTiming,
|
||||
selected,
|
||||
lockMode,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,18 +6,12 @@
|
|||
*/
|
||||
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.internal.util.MutableInteger;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||
import org.hibernate.sql.results.graph.AbstractFetchParent;
|
||||
import org.hibernate.sql.results.graph.AssemblerCreationState;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
@ -25,12 +19,8 @@ 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.Fetchable;
|
||||
import org.hibernate.sql.results.graph.basic.BasicFetch;
|
||||
import org.hibernate.sql.results.graph.basic.BasicResult;
|
||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer;
|
||||
import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
|
@ -43,22 +33,13 @@ public class EmbeddableForeignKeyResultImpl<T>
|
|||
private final String resultVariable;
|
||||
|
||||
public EmbeddableForeignKeyResultImpl(
|
||||
List<SqlSelection> sqlSelections,
|
||||
NavigablePath navigablePath,
|
||||
EmbeddableValuedModelPart embeddableValuedModelPart,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
super( embeddableValuedModelPart.getEmbeddableTypeDescriptor(), navigablePath.append( ROLE_LOCAL_NAME ) );
|
||||
this.resultVariable = resultVariable;
|
||||
fetches = new ArrayList<>();
|
||||
MutableInteger index = new MutableInteger();
|
||||
|
||||
embeddableValuedModelPart.visitFetchables(
|
||||
fetchable ->
|
||||
generateFetches( sqlSelections, navigablePath, creationState, index, fetchable )
|
||||
,
|
||||
null
|
||||
);
|
||||
this.fetches = creationState.visitFetches( this );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,62 +47,32 @@ public class EmbeddableForeignKeyResultImpl<T>
|
|||
return true;
|
||||
}
|
||||
|
||||
private void generateFetches(
|
||||
List<SqlSelection> sqlSelections,
|
||||
NavigablePath navigablePath,
|
||||
DomainResultCreationState creationState,
|
||||
MutableInteger mutableInteger,
|
||||
Fetchable fetchable) {
|
||||
if ( fetchable instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) fetchable;
|
||||
EntityMappingType associatedEntityMappingType = toOneAttributeMapping.getAssociatedEntityMappingType();
|
||||
BasicResult domainResult = new BasicResult(
|
||||
sqlSelections.get( mutableInteger.getAndIncrement() ).getValuesArrayPosition(),
|
||||
null,
|
||||
associatedEntityMappingType.getIdentifierMapping().getJavaTypeDescriptor()
|
||||
);
|
||||
Fetch fetch;
|
||||
if ( toOneAttributeMapping.getMappedFetchOptions().getTiming() == FetchTiming.DELAYED ) {
|
||||
fetch = new EntityDelayedFetchImpl(
|
||||
this,
|
||||
toOneAttributeMapping,
|
||||
navigablePath.append( fetchable.getFetchableName() ),
|
||||
domainResult
|
||||
);
|
||||
}
|
||||
else {
|
||||
fetch = new EntityFetchSelectImpl(
|
||||
this,
|
||||
toOneAttributeMapping,
|
||||
false,
|
||||
navigablePath.append( fetchable.getFetchableName() ),
|
||||
domainResult,
|
||||
false,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
fetches.add( fetch );
|
||||
}
|
||||
else {
|
||||
final Fetch fetch = new BasicFetch(
|
||||
sqlSelections.get( mutableInteger.getAndIncrement() ).getValuesArrayPosition(),
|
||||
null,
|
||||
navigablePath.append( fetchable.getFetchableName() ),
|
||||
(BasicValuedModelPart) fetchable,
|
||||
true,
|
||||
null,
|
||||
FetchTiming.IMMEDIATE,
|
||||
creationState
|
||||
);
|
||||
fetches.add( fetch );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultVariable() {
|
||||
return resultVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch generateFetchableFetch(
|
||||
Fetchable fetchable,
|
||||
NavigablePath fetchablePath,
|
||||
FetchTiming fetchTiming,
|
||||
boolean selected,
|
||||
LockMode lockMode,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
return fetchable.generateFetch(
|
||||
this,
|
||||
fetchablePath,
|
||||
fetchTiming,
|
||||
// We need to make sure to-ones are always delayed to avoid cycles while resolving entity keys
|
||||
selected && !( fetchable instanceof ToOneAttributeMapping ),
|
||||
lockMode,
|
||||
resultVariable,
|
||||
creationState
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResultAssembler<T> createResultAssembler(AssemblerCreationState creationState) {
|
||||
final EmbeddableInitializer initializer = (EmbeddableInitializer) creationState.resolveInitializer(
|
||||
|
|
|
@ -205,8 +205,8 @@ public class NonRootTablePolymorphicTests {
|
|||
assertThat( childFk.getTargetTable(), is( "sub_child" ) );
|
||||
|
||||
assertThat( childFk.getJdbcTypeCount(), is( 1 ) );
|
||||
assertThat( childFk.getKeySide().getSelectableMapping().getSelectionExpression(), is( "child_fk" ) );
|
||||
assertThat( childFk.getTargetSide().getSelectableMapping().getSelectionExpression(), is( "child_id" ) );
|
||||
assertThat( childFk.getKeySide().getSelectionExpression(), is( "child_fk" ) );
|
||||
assertThat( childFk.getTargetSide().getSelectionExpression(), is( "child_id" ) );
|
||||
|
||||
|
||||
// check Parent#sub fk
|
||||
|
@ -218,8 +218,8 @@ public class NonRootTablePolymorphicTests {
|
|||
assertThat( subFk.getTargetTable(), is( "sub" ) );
|
||||
|
||||
assertThat( subFk.getJdbcTypeCount(), is( 1 ) );
|
||||
assertThat( subFk.getKeySide().getSelectableMapping().getSelectionExpression(), is( "parent_sub_fk" ) );
|
||||
assertThat( subFk.getTargetSide().getSelectableMapping().getSelectionExpression(), is( "sub_id" ) );
|
||||
assertThat( subFk.getKeySide().getSelectionExpression(), is( "parent_sub_fk" ) );
|
||||
assertThat( subFk.getTargetSide().getSelectionExpression(), is( "sub_id" ) );
|
||||
|
||||
scope.inTransaction(
|
||||
(session) -> {
|
||||
|
|
Loading…
Reference in New Issue