HHH-8276 - Integrate LoadPlans into UniqueEntityLoader (PoC)
This commit is contained in:
parent
b10c51eec7
commit
f32c736160
|
@ -49,6 +49,7 @@ public abstract class BatchingEntityLoaderBuilder {
|
|||
}
|
||||
default: {
|
||||
return org.hibernate.loader.entity.plan.LegacyBatchingEntityLoaderBuilder.INSTANCE;
|
||||
// return LegacyBatchingEntityLoaderBuilder.INSTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -309,32 +309,32 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
|||
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositeElementDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting composite collection element for (%s)",
|
||||
StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositeElementDefinition) {
|
||||
// pop the current fetch owner, and make sure what we just popped represents this composition
|
||||
final FetchOwner poppedFetchOwner = popFromStack();
|
||||
|
||||
if ( ! CompositeElementGraph.class.isInstance( poppedFetchOwner ) ) {
|
||||
throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
|
||||
}
|
||||
|
||||
// NOTE : not much else we can really check here atm since on the walking spi side we do not have path
|
||||
|
||||
log.tracef(
|
||||
"%s Finished composite element for : %s",
|
||||
StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
// @Override
|
||||
// public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositeElementDefinition) {
|
||||
// log.tracef(
|
||||
// "%s Starting composite collection element for (%s)",
|
||||
// StringHelper.repeat( ">>", fetchOwnerStack.size() ),
|
||||
// compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositeElementDefinition) {
|
||||
// // pop the current fetch owner, and make sure what we just popped represents this composition
|
||||
// final FetchOwner poppedFetchOwner = popFromStack();
|
||||
//
|
||||
// if ( ! CompositeElementGraph.class.isInstance( poppedFetchOwner ) ) {
|
||||
// throw new WalkingException( "Mismatched FetchOwner from stack on pop" );
|
||||
// }
|
||||
//
|
||||
// // NOTE : not much else we can really check here atm since on the walking spi side we do not have path
|
||||
//
|
||||
// log.tracef(
|
||||
// "%s Finished composite element for : %s",
|
||||
// StringHelper.repeat( "<<", fetchOwnerStack.size() ),
|
||||
// compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
// );
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void finishingCollection(CollectionDefinition collectionDefinition) {
|
||||
|
|
|
@ -39,21 +39,14 @@ public abstract class AbstractCompositeEntityIdentifierDescription
|
|||
implements EntityIdentifierDescription, FetchSource, ExpandingEntityIdentifierDescription {
|
||||
|
||||
private final EntityReference entityReference;
|
||||
private final CompositeQuerySpace compositeQuerySpace;
|
||||
|
||||
protected AbstractCompositeEntityIdentifierDescription(
|
||||
EntityReference entityReference,
|
||||
CompositeQuerySpace compositeQuerySpace,
|
||||
CompositeType identifierType,
|
||||
PropertyPath propertyPath) {
|
||||
super( identifierType, propertyPath );
|
||||
super( identifierType, compositeQuerySpace, false, propertyPath );
|
||||
this.entityReference = entityReference;
|
||||
this.compositeQuerySpace = compositeQuerySpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFetchLeftHandSideUid() {
|
||||
return compositeQuerySpace.getUid();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -66,11 +59,4 @@ public abstract class AbstractCompositeEntityIdentifierDescription
|
|||
// the source for this (as a Fetch) is the entity reference
|
||||
return (FetchSource) entityReference.getIdentifierDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySpaceUid() {
|
||||
return compositeQuerySpace.getUid();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.loader.plan2.build.spi.ExpandingQuerySpace;
|
|||
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
||||
import org.hibernate.loader.plan2.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||
import org.hibernate.loader.plan2.spi.EntityFetch;
|
||||
import org.hibernate.loader.plan2.spi.Fetch;
|
||||
import org.hibernate.loader.plan2.spi.Join;
|
||||
|
@ -56,16 +57,31 @@ public abstract class AbstractCompositeFetch implements CompositeFetch, Expandin
|
|||
private static final FetchStrategy FETCH_STRATEGY = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
|
||||
|
||||
private final CompositeType compositeType;
|
||||
private final CompositeQuerySpace compositeQuerySpace;
|
||||
private final PropertyPath propertyPath;
|
||||
private final boolean allowCollectionFetches;
|
||||
|
||||
private List<Fetch> fetches;
|
||||
|
||||
protected AbstractCompositeFetch(CompositeType compositeType, PropertyPath propertyPath) {
|
||||
protected AbstractCompositeFetch(
|
||||
CompositeType compositeType,
|
||||
CompositeQuerySpace compositeQuerySpace,
|
||||
boolean allowCollectionFetches, PropertyPath propertyPath) {
|
||||
this.compositeType = compositeType;
|
||||
this.compositeQuerySpace = compositeQuerySpace;
|
||||
this.allowCollectionFetches = allowCollectionFetches;
|
||||
this.propertyPath = propertyPath;
|
||||
}
|
||||
|
||||
protected abstract String getFetchLeftHandSideUid();
|
||||
@SuppressWarnings("UnusedParameters")
|
||||
protected CompositeQuerySpace resolveCompositeQuerySpace(LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
return compositeQuerySpace;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySpaceUid() {
|
||||
return compositeQuerySpace.getUid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy, AttributeDefinition attributeDefinition) {
|
||||
|
@ -92,8 +108,8 @@ public abstract class AbstractCompositeFetch implements CompositeFetch, Expandin
|
|||
);
|
||||
}
|
||||
|
||||
final ExpandingQuerySpace leftHandSide = (ExpandingQuerySpace) loadPlanBuildingContext.getQuerySpaces().getQuerySpaceByUid(
|
||||
getFetchLeftHandSideUid()
|
||||
final ExpandingQuerySpace leftHandSide = (ExpandingQuerySpace) resolveCompositeQuerySpace(
|
||||
loadPlanBuildingContext
|
||||
);
|
||||
final Join join = leftHandSide.addEntityJoin(
|
||||
attributeDefinition,
|
||||
|
@ -122,11 +138,18 @@ public abstract class AbstractCompositeFetch implements CompositeFetch, Expandin
|
|||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
final ExpandingQuerySpace leftHandSide = (ExpandingQuerySpace) resolveCompositeQuerySpace( loadPlanBuildingContext );
|
||||
final Join join = leftHandSide.addCompositeJoin(
|
||||
attributeDefinition,
|
||||
loadPlanBuildingContext.getQuerySpaces().generateImplicitUid()
|
||||
);
|
||||
|
||||
final NestedCompositeFetchImpl fetch = new NestedCompositeFetchImpl(
|
||||
this,
|
||||
attributeDefinition.getType(),
|
||||
getPropertyPath(),
|
||||
getFetchLeftHandSideUid()
|
||||
(CompositeQuerySpace) join.getRightHandSide(),
|
||||
allowCollectionFetches,
|
||||
getPropertyPath()
|
||||
);
|
||||
addFetch( fetch );
|
||||
return fetch;
|
||||
|
@ -137,6 +160,15 @@ public abstract class AbstractCompositeFetch implements CompositeFetch, Expandin
|
|||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
if ( !allowCollectionFetches ) {
|
||||
throw new WalkingException(
|
||||
String.format(
|
||||
"This composite path [%s] does not allow collection fetches (composite id or composite collection index/element",
|
||||
propertyPath.getFullPath()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// general question here wrt Joins and collection fetches... do we create multiple Joins for many-to-many,
|
||||
// for example, or do we allow the Collection QuerySpace to handle that?
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ public abstract class AbstractEntityReference implements EntityReference, Expand
|
|||
PropertyPath propertyPath) {
|
||||
this.entityQuerySpace = entityQuerySpace;
|
||||
this.propertyPath = propertyPath;
|
||||
this.identifierDescription = buildIdentifierDescription( entityQuerySpace );
|
||||
this.identifierDescription = buildIdentifierDescription();
|
||||
}
|
||||
|
||||
|
||||
|
@ -77,11 +77,9 @@ public abstract class AbstractEntityReference implements EntityReference, Expand
|
|||
* Builds just the first level of identifier description. This will be either a simple id descriptor (String,
|
||||
* Long, etc) or some form of composite id (either encapsulated or not).
|
||||
*
|
||||
* @param querySpace The entity query space
|
||||
*
|
||||
* @return the descriptor for the identifier
|
||||
*/
|
||||
private EntityIdentifierDescription buildIdentifierDescription(EntityQuerySpace querySpace) {
|
||||
private EntityIdentifierDescription buildIdentifierDescription() {
|
||||
final EntityPersister persister = entityQuerySpace.getEntityPersister();
|
||||
final EntityIdentifierDefinition identifierDefinition = persister.getEntityKeyDefinition();
|
||||
|
||||
|
@ -166,9 +164,8 @@ public abstract class AbstractEntityReference implements EntityReference, Expand
|
|||
)
|
||||
);
|
||||
}
|
||||
final ExpandingQuerySpace leftHandSide = (ExpandingQuerySpace) loadPlanBuildingContext.getQuerySpaces().getQuerySpaceByUid(
|
||||
getQuerySpaceUid()
|
||||
);
|
||||
|
||||
final ExpandingQuerySpace leftHandSide = (ExpandingQuerySpace) entityQuerySpace;
|
||||
final Join join = leftHandSide.addEntityJoin(
|
||||
attributeDefinition,
|
||||
fetchedPersister,
|
||||
|
@ -196,9 +193,17 @@ public abstract class AbstractEntityReference implements EntityReference, Expand
|
|||
public CompositeFetch buildCompositeFetch(
|
||||
CompositionDefinition attributeDefinition,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
final ExpandingQuerySpace leftHandSide = (ExpandingQuerySpace) entityQuerySpace;
|
||||
final Join join = leftHandSide.addCompositeJoin(
|
||||
attributeDefinition,
|
||||
loadPlanBuildingContext.getQuerySpaces().generateImplicitUid()
|
||||
);
|
||||
|
||||
final CompositeFetchImpl fetch = new CompositeFetchImpl(
|
||||
this,
|
||||
attributeDefinition.getType(),
|
||||
(CompositeQuerySpace) join.getRightHandSide(),
|
||||
true,
|
||||
getPropertyPath()
|
||||
);
|
||||
addFetch( fetch );
|
||||
|
|
|
@ -23,19 +23,17 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan2.build.internal.returns;
|
||||
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
||||
import org.hibernate.loader.plan2.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan2.spi.CollectionFetchableElement;
|
||||
import org.hibernate.loader.plan2.spi.CollectionReference;
|
||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||
import org.hibernate.loader.plan2.spi.Join;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.WalkingException;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
/**
|
||||
* Models the element graph of a collection, where the elements are composite
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionFetchableElementCompositeGraph
|
||||
|
@ -43,23 +41,16 @@ public class CollectionFetchableElementCompositeGraph
|
|||
implements CompositeFetch, CollectionFetchableElement {
|
||||
|
||||
private final CollectionReference collectionReference;
|
||||
private final Join compositeJoin;
|
||||
|
||||
public CollectionFetchableElementCompositeGraph(
|
||||
CollectionReference collectionReference,
|
||||
Join compositeJoin) {
|
||||
public CollectionFetchableElementCompositeGraph(CollectionReference collectionReference, Join compositeJoin) {
|
||||
super(
|
||||
(CompositeType) compositeJoin.getRightHandSide().getPropertyMapping().getType(),
|
||||
(CompositeQuerySpace) compositeJoin.getRightHandSide(),
|
||||
false,
|
||||
// these property paths are just informational...
|
||||
collectionReference.getPropertyPath().append( "<element>" )
|
||||
);
|
||||
this.collectionReference = collectionReference;
|
||||
this.compositeJoin = compositeJoin;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFetchLeftHandSideUid() {
|
||||
return compositeJoin.getRightHandSide().getUid();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -71,17 +62,4 @@ public class CollectionFetchableElementCompositeGraph
|
|||
public FetchSource getSource() {
|
||||
return collectionReference.getElementGraph();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
throw new WalkingException( "Encountered collection as part of fetched Collection composite-element" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySpaceUid() {
|
||||
return compositeJoin.getLeftHandSide().getUid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,21 +23,19 @@
|
|||
*/
|
||||
package org.hibernate.loader.plan2.build.internal.returns;
|
||||
|
||||
import org.hibernate.engine.FetchStrategy;
|
||||
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
||||
import org.hibernate.loader.plan2.spi.CollectionFetch;
|
||||
import org.hibernate.loader.plan2.spi.CollectionFetchableIndex;
|
||||
import org.hibernate.loader.plan2.spi.CollectionReference;
|
||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||
import org.hibernate.loader.plan2.spi.Join;
|
||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||
import org.hibernate.persister.walking.spi.WalkingException;
|
||||
import org.hibernate.type.CompositeType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* Models the index graph of a collection, where the index are composite. This can only be a Map, where the keys are
|
||||
* composite
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionFetchableIndexCompositeGraph
|
||||
|
@ -45,17 +43,17 @@ public class CollectionFetchableIndexCompositeGraph
|
|||
implements CompositeFetch, CollectionFetchableIndex {
|
||||
|
||||
private final CollectionReference collectionReference;
|
||||
private final Join compositeJoin;
|
||||
|
||||
public CollectionFetchableIndexCompositeGraph(
|
||||
CollectionReference collectionReference,
|
||||
Join compositeJoin) {
|
||||
super(
|
||||
extractIndexType( compositeJoin ),
|
||||
(CompositeQuerySpace) compositeJoin.getRightHandSide(),
|
||||
false,
|
||||
collectionReference.getPropertyPath().append( "<index>" )
|
||||
);
|
||||
this.collectionReference = collectionReference;
|
||||
this.compositeJoin = compositeJoin;
|
||||
}
|
||||
|
||||
private static CompositeType extractIndexType(Join compositeJoin) {
|
||||
|
@ -67,12 +65,6 @@ public class CollectionFetchableIndexCompositeGraph
|
|||
throw new IllegalArgumentException( "Could note extract collection composite-index" );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected String getFetchLeftHandSideUid() {
|
||||
return compositeJoin.getRightHandSide().getUid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionReference getCollectionReference() {
|
||||
return collectionReference;
|
||||
|
@ -82,24 +74,4 @@ public class CollectionFetchableIndexCompositeGraph
|
|||
public FetchSource getSource() {
|
||||
return collectionReference.getIndexGraph();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateFetchPlan(FetchStrategy fetchStrategy, AttributeDefinition attributeDefinition) {
|
||||
// metamodel should already disallow collections to be defined as part of a collection composite-index
|
||||
// so, nothing to do here
|
||||
super.validateFetchPlan( fetchStrategy, attributeDefinition );
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionFetch buildCollectionFetch(
|
||||
AssociationAttributeDefinition attributeDefinition,
|
||||
FetchStrategy fetchStrategy,
|
||||
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||
throw new WalkingException( "Encountered collection as part of the Map composite-index" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySpaceUid() {
|
||||
return compositeJoin.getRightHandSide().getUid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ package org.hibernate.loader.plan2.build.internal.returns;
|
|||
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
|
@ -33,28 +33,20 @@ import org.hibernate.type.CompositeType;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CompositeFetchImpl extends AbstractCompositeFetch implements CompositeFetch {
|
||||
private final EntityReference source;
|
||||
private final FetchSource source;
|
||||
|
||||
protected CompositeFetchImpl(
|
||||
EntityReference source,
|
||||
FetchSource source,
|
||||
CompositeType compositeType,
|
||||
CompositeQuerySpace compositeQuerySpace,
|
||||
boolean allowCollectionFetches,
|
||||
PropertyPath propertyPath) {
|
||||
super( compositeType, propertyPath );
|
||||
super( compositeType, compositeQuerySpace, allowCollectionFetches, propertyPath );
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFetchLeftHandSideUid() {
|
||||
return getSource().getQuerySpaceUid();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchSource getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySpaceUid() {
|
||||
return source.getQuerySpaceUid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,15 +30,28 @@ import org.hibernate.loader.plan2.spi.EntityReference;
|
|||
import org.hibernate.type.CompositeType;
|
||||
|
||||
/**
|
||||
* Models a composite entity identifier that is encapsulated (meaning there is a composite class and a single
|
||||
* attribute that encapsulates the composite value).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class EncapsulatedEntityIdentifierDescription
|
||||
extends AbstractCompositeEntityIdentifierDescription
|
||||
implements ExpandingEntityIdentifierDescription {
|
||||
|
||||
/**
|
||||
* Build an encapsulated version of a composite EntityIdentifierDescription
|
||||
*
|
||||
* @param entityReference The entity whose identifier we describe
|
||||
* @param compositeQuerySpace The query space we are mapped to.
|
||||
* @param compositeType The type representing this composition
|
||||
* @param propertyPath The property path (informational)
|
||||
*/
|
||||
protected EncapsulatedEntityIdentifierDescription(
|
||||
EntityReference entityReference,
|
||||
CompositeQuerySpace compositeQuerySpace,
|
||||
CompositeType identifierType, PropertyPath propertyPath) {
|
||||
super( entityReference, compositeQuerySpace, identifierType, propertyPath );
|
||||
CompositeType compositeType,
|
||||
PropertyPath propertyPath) {
|
||||
super( entityReference, compositeQuerySpace, compositeType, propertyPath );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ package org.hibernate.loader.plan2.build.internal.returns;
|
|||
|
||||
import org.hibernate.loader.PropertyPath;
|
||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||
import org.hibernate.type.CompositeType;
|
||||
|
||||
|
@ -33,30 +34,18 @@ import org.hibernate.type.CompositeType;
|
|||
*/
|
||||
public class NestedCompositeFetchImpl extends AbstractCompositeFetch {
|
||||
private final CompositeFetch source;
|
||||
private final String fetchLeftHandSideUid;
|
||||
|
||||
public NestedCompositeFetchImpl(
|
||||
CompositeFetch source,
|
||||
CompositeType type,
|
||||
PropertyPath propertyPath,
|
||||
String fetchLeftHandSideUid) {
|
||||
super( type, propertyPath );
|
||||
CompositeQuerySpace compositeQuerySpace,
|
||||
boolean allowCollectionFetches, PropertyPath propertyPath) {
|
||||
super( type, compositeQuerySpace, allowCollectionFetches, propertyPath );
|
||||
this.source = source;
|
||||
this.fetchLeftHandSideUid = fetchLeftHandSideUid;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getFetchLeftHandSideUid() {
|
||||
return fetchLeftHandSideUid;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchSource getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQuerySpaceUid() {
|
||||
return source.getQuerySpaceUid();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,9 +29,20 @@ import org.hibernate.loader.plan2.spi.EntityReference;
|
|||
import org.hibernate.type.CompositeType;
|
||||
|
||||
/**
|
||||
* Models a composite entity identifier that is non-encapsulated (meaning there is no composite class, no
|
||||
* single attribute that encapsulates the composite value).
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NonEncapsulatedEntityIdentifierDescription extends AbstractCompositeEntityIdentifierDescription {
|
||||
/**
|
||||
* Build a non-encapsulated version of a composite EntityIdentifierDescription
|
||||
*
|
||||
* @param entityReference The entity whose identifier we describe
|
||||
* @param compositeQuerySpace The query space we are mapped to.
|
||||
* @param compositeType The type representing this composition
|
||||
* @param propertyPath The property path (informational)
|
||||
*/
|
||||
public NonEncapsulatedEntityIdentifierDescription(
|
||||
EntityReference entityReference,
|
||||
CompositeQuerySpace compositeQuerySpace,
|
||||
|
|
|
@ -58,7 +58,6 @@ import org.hibernate.persister.walking.spi.AttributeDefinition;
|
|||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositeCollectionElementDefinition;
|
||||
import org.hibernate.persister.walking.spi.CompositionDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||
|
@ -201,7 +200,13 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
final ExpandingFetchSource fetchSource = popFromStack();
|
||||
|
||||
if ( ! EntityReference.class.isInstance( fetchSource ) ) {
|
||||
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
|
||||
throw new WalkingException(
|
||||
String.format(
|
||||
"Mismatched FetchSource from stack on pop. Expecting EntityReference(%s), but found %s",
|
||||
entityDefinition.getEntityPersister().getEntityName(),
|
||||
fetchSource
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
final EntityReference entityReference = (EntityReference) fetchSource;
|
||||
|
@ -366,39 +371,79 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
final Type indexType = collectionIndexDefinition.getType();
|
||||
if ( indexType.isAssociationType() || indexType.isComponentType() ) {
|
||||
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
|
||||
final CollectionFetchableIndex indexGraph = collectionReference.getIndexGraph();
|
||||
public void startingCollectionIndex(CollectionIndexDefinition indexDefinition) {
|
||||
final Type indexType = indexDefinition.getType();
|
||||
if ( indexType.isAnyType() ) {
|
||||
throw new WalkingException( "CollectionIndexDefinition reported any-type mapping as map index" );
|
||||
}
|
||||
|
||||
log.tracef(
|
||||
"%s Starting collection index graph : %s",
|
||||
StringHelper.repeat( ">>", fetchSourceStack.size() ),
|
||||
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
|
||||
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
|
||||
final CollectionFetchableIndex indexGraph = collectionReference.getIndexGraph();
|
||||
|
||||
if ( indexType.isEntityType() || indexType.isComponentType() ) {
|
||||
if ( indexGraph == null ) {
|
||||
throw new WalkingException( "Collection reference did not return index handler" );
|
||||
throw new WalkingException(
|
||||
"CollectionReference did not return an expected index graph : " +
|
||||
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
pushToStack( (ExpandingFetchSource) indexGraph );
|
||||
}
|
||||
else {
|
||||
if ( indexGraph != null ) {
|
||||
throw new WalkingException(
|
||||
"CollectionReference returned an unexpected index graph : " +
|
||||
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition) {
|
||||
// nothing to do here
|
||||
// - the element graph pushed while starting would be popped in finishingEntity/finishingComposite
|
||||
public void finishingCollectionIndex(CollectionIndexDefinition indexDefinition) {
|
||||
final Type indexType = indexDefinition.getType();
|
||||
if ( indexType.isComponentType() ) {
|
||||
// todo : validate the stack?
|
||||
popFromStack();
|
||||
|
||||
}
|
||||
|
||||
// entity indexes would be popped during finishingEntity processing
|
||||
|
||||
log.tracef(
|
||||
"%s Finished collection index graph : %s",
|
||||
StringHelper.repeat( "<<", fetchSourceStack.size() ),
|
||||
indexDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingCollectionElements(CollectionElementDefinition elementDefinition) {
|
||||
final Type elementType = elementDefinition.getType();
|
||||
if ( elementType.isAnyType() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
log.tracef(
|
||||
"%s Starting collection element graph : %s",
|
||||
StringHelper.repeat( ">>", fetchSourceStack.size() ),
|
||||
elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
|
||||
final CollectionReference collectionReference = collectionReferenceStack.peekFirst();
|
||||
final CollectionFetchableElement elementGraph = collectionReference.getElementGraph();
|
||||
|
||||
final Type elementType = elementDefinition.getType();
|
||||
final boolean expectFetchSourceElements =
|
||||
( elementType.isAssociationType() || elementType.isComponentType() )
|
||||
&& ! elementType.isAnyType();
|
||||
|
||||
if ( expectFetchSourceElements ) {
|
||||
if ( elementType.isAssociationType() || elementType.isComponentType() ) {
|
||||
if ( elementGraph == null ) {
|
||||
throw new IllegalStateException(
|
||||
"Expecting CollectionFetchableElement, but element graph was null : "
|
||||
+ elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
"CollectionReference did not return an expected element graph : " +
|
||||
elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -407,8 +452,8 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
else {
|
||||
if ( elementGraph != null ) {
|
||||
throw new IllegalStateException(
|
||||
"Not expecting CollectionFetchableElement, but element graph was non-null : "
|
||||
+ elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
"CollectionReference returned an unexpected element graph : " +
|
||||
elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -416,41 +461,31 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
|
||||
@Override
|
||||
public void finishingCollectionElements(CollectionElementDefinition elementDefinition) {
|
||||
// nothing to do here
|
||||
// - the element graph pushed while starting would be popped in finishing/Entity/finishingComposite
|
||||
}
|
||||
final Type elementType = elementDefinition.getType();
|
||||
if ( elementType.isComponentType() ) {
|
||||
// pop it from the stack
|
||||
final ExpandingFetchSource popped = popFromStack();
|
||||
|
||||
@Override
|
||||
public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositeElementDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting composite collection element for (%s)",
|
||||
StringHelper.repeat( ">>", fetchSourceStack.size() ),
|
||||
compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
// validation
|
||||
|
||||
@Override
|
||||
public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositeElementDefinition) {
|
||||
// pop the current fetch owner, and make sure what we just popped represents this composition
|
||||
final ExpandingFetchSource popped = popFromStack();
|
||||
|
||||
if ( ! CollectionFetchableElement.class.isInstance( popped ) ) {
|
||||
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
|
||||
if ( ! CollectionFetchableElement.class.isInstance( popped ) ) {
|
||||
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE : not much else we can really check here atm since on the walking spi side we do not have path
|
||||
// entity indexes would be popped during finishingEntity processing
|
||||
|
||||
log.tracef(
|
||||
"%s Finished composite element for : %s",
|
||||
"%s Finished collection element graph : %s",
|
||||
StringHelper.repeat( "<<", fetchSourceStack.size() ),
|
||||
compositeElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
elementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startingComposite(CompositionDefinition compositionDefinition) {
|
||||
log.tracef(
|
||||
"%s Starting composition : %s",
|
||||
"%s Starting composite : %s",
|
||||
StringHelper.repeat( ">>", fetchSourceStack.size() ),
|
||||
compositionDefinition.getName()
|
||||
);
|
||||
|
@ -458,6 +493,9 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
if ( fetchSourceStack.isEmpty() ) {
|
||||
throw new HibernateException( "A component cannot be the root of a walk nor a graph" );
|
||||
}
|
||||
|
||||
final CompositeFetch compositeFetch = currentSource().buildCompositeFetch( compositionDefinition, this );
|
||||
pushToStack( (ExpandingFetchSource) compositeFetch );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -469,10 +507,8 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
throw new WalkingException( "Mismatched FetchSource from stack on pop" );
|
||||
}
|
||||
|
||||
// NOTE : not much else we can really check here atm since on the walking spi side we do not have path
|
||||
|
||||
log.tracef(
|
||||
"%s Finished composition : %s",
|
||||
"%s Finishing composite : %s",
|
||||
StringHelper.repeat( "<<", fetchSourceStack.size() ),
|
||||
compositionDefinition.getName()
|
||||
);
|
||||
|
@ -672,9 +708,9 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
|||
}
|
||||
|
||||
protected boolean handleCompositeAttribute(CompositionDefinition attributeDefinition) {
|
||||
final ExpandingFetchSource currentSource = currentSource();
|
||||
final CompositeFetch fetch = currentSource.buildCompositeFetch( attributeDefinition, this );
|
||||
pushToStack( (ExpandingFetchSource) fetch );
|
||||
// final ExpandingFetchSource currentSource = currentSource();
|
||||
// final CompositeFetch fetch = currentSource.buildCompositeFetch( attributeDefinition, this );
|
||||
// pushToStack( (ExpandingFetchSource) fetch );
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -272,7 +272,10 @@ public class LoadQueryJoinAndFetchProcessor {
|
|||
//
|
||||
// long story short, for now we'll use an assumption that the last join in the CollectionQuerySpace is the
|
||||
// element join (that's how the joins are built as of now..)
|
||||
// todo : remove this assumption ^^
|
||||
//
|
||||
// todo : remove this assumption ^^; maybe we make CollectionQuerySpace "special" and rather than have it
|
||||
// hold a list of joins, we have it expose the 2 (index, element) separately.
|
||||
|
||||
Join collectionElementJoin = null;
|
||||
for ( Join collectionJoin : rightHandSide.getJoins() ) {
|
||||
collectionElementJoin = collectionJoin;
|
||||
|
|
|
@ -49,7 +49,7 @@ public interface AssociationVisitationStrategy {
|
|||
/**
|
||||
* Notification we are starting to walk an entity.
|
||||
*
|
||||
* @param entityDefinition The entity we are starting to walk
|
||||
* @param entityDefinition The entity we are preparing to walk
|
||||
*/
|
||||
public void startingEntity(EntityDefinition entityDefinition);
|
||||
|
||||
|
@ -63,7 +63,7 @@ public interface AssociationVisitationStrategy {
|
|||
/**
|
||||
* Notification we are starting to walk the identifier of an entity.
|
||||
*
|
||||
* @param entityIdentifierDefinition The identifier we are starting to walk
|
||||
* @param entityIdentifierDefinition The identifier we are preparing to walk
|
||||
*/
|
||||
public void startingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
|
||||
|
||||
|
@ -74,22 +74,93 @@ public interface AssociationVisitationStrategy {
|
|||
*/
|
||||
public void finishingEntityIdentifier(EntityIdentifierDefinition entityIdentifierDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are starting to walk a collection
|
||||
*
|
||||
* @param collectionDefinition The collection we are preparing to walk
|
||||
*/
|
||||
public void startingCollection(CollectionDefinition collectionDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are finishing walking a collection
|
||||
*
|
||||
* @param collectionDefinition The collection we are finishing
|
||||
*/
|
||||
public void finishingCollection(CollectionDefinition collectionDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are starting to walk the index of a collection (List/Map). In the case of a Map,
|
||||
* if the indices (the keys) are entities this will be followed up by a call to {@link #startingEntity}
|
||||
*
|
||||
* @param collectionIndexDefinition The collection index we are preparing to walk.
|
||||
*/
|
||||
public void startingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are finishing walking the index of a collection (List/Map).
|
||||
*
|
||||
* @param collectionIndexDefinition The collection index we are finishing
|
||||
*/
|
||||
public void finishingCollectionIndex(CollectionIndexDefinition collectionIndexDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are starting to look at the element definition for the collection. If the collection
|
||||
* elements are entities this will be followed up by a call to {@link #startingEntity}
|
||||
*
|
||||
* @param elementDefinition The collection element we are preparing to walk..
|
||||
*/
|
||||
public void startingCollectionElements(CollectionElementDefinition elementDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are finishing walking the elements of a collection (List/Map).
|
||||
*
|
||||
* @param elementDefinition The collection element we are finishing
|
||||
*/
|
||||
public void finishingCollectionElements(CollectionElementDefinition elementDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are preparing to walk a composite. This is called only for:<ul>
|
||||
* <li>
|
||||
* top-level composites for entity attributes. composite entity identifiers do not route through here, see
|
||||
* {@link #startingEntityIdentifier} if you need to hook into walking the top-level cid composite.
|
||||
* </li>
|
||||
* <li>
|
||||
* All forms of nested composite paths
|
||||
* </li>
|
||||
* </ul>
|
||||
*
|
||||
* @param compositionDefinition The composite we are preparing to walk.
|
||||
*/
|
||||
public void startingComposite(CompositionDefinition compositionDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are done walking a composite. Called on the back-end of the situations listed
|
||||
* on {@link #startingComposite}
|
||||
*
|
||||
* @param compositionDefinition The composite we are finishing
|
||||
*/
|
||||
public void finishingComposite(CompositionDefinition compositionDefinition);
|
||||
|
||||
public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition);
|
||||
public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition);
|
||||
// get rid of these ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition);
|
||||
// public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition);
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
/**
|
||||
* Notification that we are preparing to walk an attribute. May be followed by calls to {@link #startingEntity}
|
||||
* (one-to-one, many-to-one), {@link #startingComposite}, or {@link #startingCollection}.
|
||||
*
|
||||
* @param attributeDefinition The attribute we are preparing to walk.
|
||||
*
|
||||
* @return {@code true} if the walking should continue; {@code false} if walking should stop.
|
||||
*/
|
||||
public boolean startingAttribute(AttributeDefinition attributeDefinition);
|
||||
|
||||
/**
|
||||
* Notification that we are finishing walking an attribute.
|
||||
*
|
||||
* @param attributeDefinition The attribute we are done walking
|
||||
*/
|
||||
public void finishingAttribute(AttributeDefinition attributeDefinition);
|
||||
|
||||
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition);
|
||||
|
|
|
@ -118,6 +118,8 @@ public class MetamodelGraphWalker {
|
|||
// to make encapsulated and non-encapsulated composite identifiers work the same here, we "cheat" here a
|
||||
// little bit and simply walk the attributes of the composite id in both cases.
|
||||
|
||||
// this works because the LoadPlans already build the top-level composite for composite ids
|
||||
|
||||
if ( identifierDefinition.isEncapsulated() ) {
|
||||
// in the encapsulated composite id case that means we have a little bit of duplication between here and
|
||||
// visitCompositeDefinition, but in the spirit of consistently handling composite ids, that is much better
|
||||
|
@ -125,12 +127,12 @@ public class MetamodelGraphWalker {
|
|||
final EncapsulatedEntityIdentifierDefinition idAsEncapsulated = (EncapsulatedEntityIdentifierDefinition) identifierDefinition;
|
||||
final AttributeDefinition idAttr = idAsEncapsulated.getAttributeDefinition();
|
||||
if ( CompositionDefinition.class.isInstance( idAttr ) ) {
|
||||
visitCompositeDefinition( (CompositionDefinition) idAttr );
|
||||
visitAttributes( (CompositionDefinition) idAttr );
|
||||
}
|
||||
}
|
||||
else {
|
||||
// NonEncapsulatedEntityIdentifierDefinition itself is defined as a CompositionDefinition
|
||||
visitCompositeDefinition( (NonEncapsulatedEntityIdentifierDefinition) identifierDefinition );
|
||||
visitAttributes( (NonEncapsulatedEntityIdentifierDefinition) identifierDefinition );
|
||||
}
|
||||
|
||||
strategy.finishingEntityIdentifier( identifierDefinition );
|
||||
|
@ -252,7 +254,7 @@ public class MetamodelGraphWalker {
|
|||
strategy.startingCollectionElements( elementDefinition );
|
||||
|
||||
if ( elementDefinition.getType().isComponentType() ) {
|
||||
visitCompositeCollectionElementDefinition( elementDefinition.toCompositeElementDefinition() );
|
||||
visitAttributes( elementDefinition.toCompositeElementDefinition() );
|
||||
}
|
||||
else if ( elementDefinition.getType().isEntityType() ) {
|
||||
visitEntityDefinition( elementDefinition.toEntityDefinition() );
|
||||
|
@ -261,14 +263,6 @@ public class MetamodelGraphWalker {
|
|||
strategy.finishingCollectionElements( elementDefinition );
|
||||
}
|
||||
|
||||
private void visitCompositeCollectionElementDefinition(CompositeCollectionElementDefinition compositionElementDefinition) {
|
||||
strategy.startingCompositeCollectionElement( compositionElementDefinition );
|
||||
|
||||
visitAttributes( compositionElementDefinition );
|
||||
|
||||
strategy.finishingCompositeCollectionElement( compositionElementDefinition );
|
||||
}
|
||||
|
||||
private final Set<AssociationKey> visitedAssociationKeys = new HashSet<AssociationKey>();
|
||||
|
||||
/**
|
||||
|
|
|
@ -64,10 +64,15 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
cfg.addResource( "org/hibernate/test/onetoone/joined/Person.hbm.xml" );
|
||||
SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
|
||||
// doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.joined.Person.class ) );
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.joined.Entity.class ) );
|
||||
try {
|
||||
// doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.joined.Person.class ) );
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.joined.Entity.class ) );
|
||||
|
||||
// doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.joined.Address.class ) );
|
||||
// doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.joined.Address.class ) );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -77,7 +82,12 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
cfg.addResource( "org/hibernate/test/onetoone/formula/Person.hbm.xml" );
|
||||
SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.formula.Person.class ) );
|
||||
try {
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.onetoone.formula.Person.class ) );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -88,8 +98,14 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
cfg.addAnnotatedClass( EncapsulatedCompositeIdResultSetProcessorTest.CardField.class );
|
||||
cfg.addAnnotatedClass( EncapsulatedCompositeIdResultSetProcessorTest.Card.class );
|
||||
SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( EncapsulatedCompositeIdResultSetProcessorTest.CardField.class ) );
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( EncapsulatedCompositeIdResultSetProcessorTest.Card.class ) );
|
||||
|
||||
try {
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( EncapsulatedCompositeIdResultSetProcessorTest.CardField.class ) );
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( EncapsulatedCompositeIdResultSetProcessorTest.Card.class ) );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -99,7 +115,13 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
Configuration cfg = new Configuration();
|
||||
cfg.addAnnotatedClass( EncapsulatedCompositeIdResultSetProcessorTest.Parent.class );
|
||||
SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( EncapsulatedCompositeIdResultSetProcessorTest.Parent.class ) );
|
||||
|
||||
try {
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( EncapsulatedCompositeIdResultSetProcessorTest.Parent.class ) );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -112,48 +134,53 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
|
||||
SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
|
||||
final OuterJoinLoadable cardFieldPersister = (OuterJoinLoadable) sf.getClassMetadata( CardField.class );
|
||||
doCompare( sf, cardFieldPersister );
|
||||
try {
|
||||
final OuterJoinLoadable cardFieldPersister = (OuterJoinLoadable) sf.getClassMetadata( CardField.class );
|
||||
doCompare( sf, cardFieldPersister );
|
||||
|
||||
final LoadPlan loadPlan = LoadPlanStructureAssertionHelper.INSTANCE.buildLoadPlan( sf, cardFieldPersister );
|
||||
assertEquals( LoadPlan.Disposition.ENTITY_LOADER, loadPlan.getDisposition() );
|
||||
assertEquals( 1, loadPlan.getReturns().size() );
|
||||
final EntityReturn cardFieldReturn = assertTyping( EntityReturn.class, loadPlan.getReturns().get( 0 ) );
|
||||
assertEquals( 0, cardFieldReturn.getFetches().length );
|
||||
final LoadPlan loadPlan = LoadPlanStructureAssertionHelper.INSTANCE.buildLoadPlan( sf, cardFieldPersister );
|
||||
assertEquals( LoadPlan.Disposition.ENTITY_LOADER, loadPlan.getDisposition() );
|
||||
assertEquals( 1, loadPlan.getReturns().size() );
|
||||
final EntityReturn cardFieldReturn = assertTyping( EntityReturn.class, loadPlan.getReturns().get( 0 ) );
|
||||
assertEquals( 0, cardFieldReturn.getFetches().length );
|
||||
|
||||
// CardField defines a composite pk with 2 fetches : Card and Key (the id description acts as the composite)
|
||||
assertTrue( cardFieldReturn.getIdentifierDescription().hasFetches() );
|
||||
final FetchSource cardFieldIdAsFetchSource = assertTyping( FetchSource.class, cardFieldReturn.getIdentifierDescription() );
|
||||
assertEquals( 2, cardFieldIdAsFetchSource.getFetches().length );
|
||||
// CardField defines a composite pk with 2 fetches : Card and Key (the id description acts as the composite)
|
||||
assertTrue( cardFieldReturn.getIdentifierDescription().hasFetches() );
|
||||
final FetchSource cardFieldIdAsFetchSource = assertTyping( FetchSource.class, cardFieldReturn.getIdentifierDescription() );
|
||||
assertEquals( 2, cardFieldIdAsFetchSource.getFetches().length );
|
||||
|
||||
// First the key-many-to-one to Card...
|
||||
final EntityFetch cardFieldIdCardFetch = assertTyping(
|
||||
EntityFetch.class,
|
||||
cardFieldIdAsFetchSource.getFetches()[0]
|
||||
);
|
||||
assertFalse( cardFieldIdCardFetch.getIdentifierDescription().hasFetches() );
|
||||
// i think this one might be a mistake; i think the collection reader still needs to be registered. Its zero
|
||||
// because the inverse of the key-many-to-one already had a registered AssociationKey and so saw the
|
||||
// CollectionFetch as a circularity (I think)
|
||||
assertEquals( 0, cardFieldIdCardFetch.getFetches().length );
|
||||
// First the key-many-to-one to Card...
|
||||
final EntityFetch cardFieldIdCardFetch = assertTyping(
|
||||
EntityFetch.class,
|
||||
cardFieldIdAsFetchSource.getFetches()[0]
|
||||
);
|
||||
assertFalse( cardFieldIdCardFetch.getIdentifierDescription().hasFetches() );
|
||||
// i think this one might be a mistake; i think the collection reader still needs to be registered. Its zero
|
||||
// because the inverse of the key-many-to-one already had a registered AssociationKey and so saw the
|
||||
// CollectionFetch as a circularity (I think)
|
||||
assertEquals( 0, cardFieldIdCardFetch.getFetches().length );
|
||||
|
||||
// then the Key..
|
||||
final EntityFetch cardFieldIdKeyFetch = assertTyping(
|
||||
EntityFetch.class,
|
||||
cardFieldIdAsFetchSource.getFetches()[1]
|
||||
);
|
||||
assertFalse( cardFieldIdKeyFetch.getIdentifierDescription().hasFetches() );
|
||||
assertEquals( 0, cardFieldIdKeyFetch.getFetches().length );
|
||||
// then the Key..
|
||||
final EntityFetch cardFieldIdKeyFetch = assertTyping(
|
||||
EntityFetch.class,
|
||||
cardFieldIdAsFetchSource.getFetches()[1]
|
||||
);
|
||||
assertFalse( cardFieldIdKeyFetch.getIdentifierDescription().hasFetches() );
|
||||
assertEquals( 0, cardFieldIdKeyFetch.getFetches().length );
|
||||
|
||||
|
||||
// we need the readers ordered in a certain manner. Here specifically: Fetch(Card), Fetch(Key), Return(CardField)
|
||||
//
|
||||
// additionally, we need Fetch(Card) and Fetch(Key) to be hydrated/semi-resolved before attempting to
|
||||
// resolve the EntityKey for Return(CardField)
|
||||
//
|
||||
// together those sound like argument enough to continue keeping readers for "identifier fetches" as part of
|
||||
// a special "identifier reader". generated aliases could help here too to remove cyclic-ness from the graph.
|
||||
// but at any rate, we need to know still when this becomes circularity
|
||||
// we need the readers ordered in a certain manner. Here specifically: Fetch(Card), Fetch(Key), Return(CardField)
|
||||
//
|
||||
// additionally, we need Fetch(Card) and Fetch(Key) to be hydrated/semi-resolved before attempting to
|
||||
// resolve the EntityKey for Return(CardField)
|
||||
//
|
||||
// together those sound like argument enough to continue keeping readers for "identifier fetches" as part of
|
||||
// a special "identifier reader". generated aliases could help here too to remove cyclic-ness from the graph.
|
||||
// but at any rate, we need to know still when this becomes circularity
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -165,46 +192,52 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
cfg.addAnnotatedClass( PrimaryKey.class );
|
||||
|
||||
final SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
final OuterJoinLoadable cardPersister = (OuterJoinLoadable) sf.getClassMetadata( Card.class );
|
||||
doCompare( sf, cardPersister );
|
||||
|
||||
final LoadPlan cardLoadPlan = LoadPlanStructureAssertionHelper.INSTANCE.buildLoadPlan( sf, cardPersister );
|
||||
assertEquals( LoadPlan.Disposition.ENTITY_LOADER, cardLoadPlan.getDisposition() );
|
||||
assertEquals( 1, cardLoadPlan.getReturns().size() );
|
||||
try {
|
||||
final OuterJoinLoadable cardPersister = (OuterJoinLoadable) sf.getClassMetadata( Card.class );
|
||||
doCompare( sf, cardPersister );
|
||||
|
||||
// Check the root EntityReturn(Card)
|
||||
final EntityReturn cardReturn = assertTyping( EntityReturn.class, cardLoadPlan.getReturns().get( 0 ) );
|
||||
assertFalse( cardReturn.getIdentifierDescription().hasFetches() );
|
||||
final LoadPlan cardLoadPlan = LoadPlanStructureAssertionHelper.INSTANCE.buildLoadPlan( sf, cardPersister );
|
||||
assertEquals( LoadPlan.Disposition.ENTITY_LOADER, cardLoadPlan.getDisposition() );
|
||||
assertEquals( 1, cardLoadPlan.getReturns().size() );
|
||||
|
||||
// Card should have one fetch, the fields collection
|
||||
assertEquals( 1, cardReturn.getFetches().length );
|
||||
final CollectionFetch fieldsFetch = assertTyping( CollectionFetch.class, cardReturn.getFetches()[0] );
|
||||
assertNotNull( fieldsFetch.getElementGraph() );
|
||||
// Check the root EntityReturn(Card)
|
||||
final EntityReturn cardReturn = assertTyping( EntityReturn.class, cardLoadPlan.getReturns().get( 0 ) );
|
||||
assertFalse( cardReturn.getIdentifierDescription().hasFetches() );
|
||||
|
||||
// the Card.fields collection has entity elements of type CardField...
|
||||
final CollectionFetchableElementEntityGraph cardFieldElementGraph = assertTyping( CollectionFetchableElementEntityGraph.class, fieldsFetch.getElementGraph() );
|
||||
// CardField should have no fetches
|
||||
assertEquals( 0, cardFieldElementGraph.getFetches().length );
|
||||
// But it should have 1 key-many-to-one fetch for Key (Card is already handled)
|
||||
assertTrue( cardFieldElementGraph.getIdentifierDescription().hasFetches() );
|
||||
final FetchSource cardFieldElementGraphIdAsFetchSource = assertTyping(
|
||||
FetchSource.class,
|
||||
cardFieldElementGraph.getIdentifierDescription()
|
||||
);
|
||||
assertEquals( 1, cardFieldElementGraphIdAsFetchSource.getFetches().length );
|
||||
// Card should have one fetch, the fields collection
|
||||
assertEquals( 1, cardReturn.getFetches().length );
|
||||
final CollectionFetch fieldsFetch = assertTyping( CollectionFetch.class, cardReturn.getFetches()[0] );
|
||||
assertNotNull( fieldsFetch.getElementGraph() );
|
||||
|
||||
// BidirectionalEntityFetch circularCardFetch = assertTyping(
|
||||
// BidirectionalEntityFetch.class,
|
||||
// fieldsElementCompositeIdFetch.getFetches()[0]
|
||||
// );
|
||||
// assertSame( circularCardFetch.getTargetEntityReference(), cardReturn );
|
||||
// the Card.fields collection has entity elements of type CardField...
|
||||
final CollectionFetchableElementEntityGraph cardFieldElementGraph = assertTyping( CollectionFetchableElementEntityGraph.class, fieldsFetch.getElementGraph() );
|
||||
// CardField should have no fetches
|
||||
assertEquals( 0, cardFieldElementGraph.getFetches().length );
|
||||
// But it should have 1 key-many-to-one fetch for Key (Card is already handled)
|
||||
assertTrue( cardFieldElementGraph.getIdentifierDescription().hasFetches() );
|
||||
final FetchSource cardFieldElementGraphIdAsFetchSource = assertTyping(
|
||||
FetchSource.class,
|
||||
cardFieldElementGraph.getIdentifierDescription()
|
||||
);
|
||||
assertEquals( 1, cardFieldElementGraphIdAsFetchSource.getFetches().length );
|
||||
|
||||
// the fetch above is to the other key-many-to-one for CardField.primaryKey composite: key
|
||||
EntityFetch keyFetch = assertTyping(
|
||||
EntityFetch.class,
|
||||
cardFieldElementGraphIdAsFetchSource.getFetches()[0]
|
||||
);
|
||||
assertEquals( Key.class.getName(), keyFetch.getEntityPersister().getEntityName() );
|
||||
// BidirectionalEntityFetch circularCardFetch = assertTyping(
|
||||
// BidirectionalEntityFetch.class,
|
||||
// fieldsElementCompositeIdFetch.getFetches()[0]
|
||||
// );
|
||||
// assertSame( circularCardFetch.getTargetEntityReference(), cardReturn );
|
||||
|
||||
// the fetch above is to the other key-many-to-one for CardField.primaryKey composite: key
|
||||
EntityFetch keyFetch = assertTyping(
|
||||
EntityFetch.class,
|
||||
cardFieldElementGraphIdAsFetchSource.getFetches()[0]
|
||||
);
|
||||
assertEquals( Key.class.getName(), keyFetch.getEntityPersister().getEntityName() );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -212,7 +245,13 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
|||
Configuration cfg = new Configuration();
|
||||
cfg.addResource( "org/hibernate/test/immutable/entitywithmutablecollection/inverse/ContractVariation.hbm.xml" );
|
||||
SessionFactoryImplementor sf = (SessionFactoryImplementor) cfg.buildSessionFactory();
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.immutable.entitywithmutablecollection.Contract.class ) );
|
||||
|
||||
try {
|
||||
doCompare( sf, (OuterJoinLoadable) sf.getClassMetadata( org.hibernate.test.immutable.entitywithmutablecollection.Contract.class ) );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -45,8 +45,12 @@ public class CompositesWalkingTest extends BaseUnitTestCase {
|
|||
final SessionFactory sf = new Configuration()
|
||||
.addAnnotatedClass( TestCourse.class )
|
||||
.buildSessionFactory();
|
||||
final EntityPersister ep = (EntityPersister) sf.getClassMetadata( TestCourse.class );
|
||||
|
||||
MetamodelGraphWalker.visitEntity( new LoggingAssociationVisitationStrategy(), ep );
|
||||
try {
|
||||
final EntityPersister ep = (EntityPersister) sf.getClassMetadata( TestCourse.class );
|
||||
MetamodelGraphWalker.visitEntity( new LoggingAssociationVisitationStrategy(), ep );
|
||||
}
|
||||
finally {
|
||||
sf.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -131,7 +131,7 @@ public class LoggingAssociationVisitationStrategy implements AssociationVisitati
|
|||
System.out.println(
|
||||
String.format(
|
||||
"%s Finishing composite (%s)",
|
||||
StringHelper.repeat( ">>", depth-- ),
|
||||
StringHelper.repeat( "<<", depth-- ),
|
||||
compositionDefinition.getName()
|
||||
)
|
||||
);
|
||||
|
@ -206,28 +206,28 @@ public class LoggingAssociationVisitationStrategy implements AssociationVisitati
|
|||
|
||||
|
||||
// why do we have these + startingCollectionElements/finishingCollectionElements ???
|
||||
|
||||
@Override
|
||||
public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition) {
|
||||
System.out.println(
|
||||
String.format(
|
||||
"%s Starting composite (%s)",
|
||||
StringHelper.repeat( ">>", ++depth ),
|
||||
compositionElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition) {
|
||||
System.out.println(
|
||||
String.format(
|
||||
"%s Finishing composite (%s)",
|
||||
StringHelper.repeat( "<<", depth-- ),
|
||||
compositionElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
)
|
||||
);
|
||||
}
|
||||
//
|
||||
// @Override
|
||||
// public void startingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition) {
|
||||
// System.out.println(
|
||||
// String.format(
|
||||
// "%s Starting composite (%s)",
|
||||
// StringHelper.repeat( ">>", ++depth ),
|
||||
// compositionElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public void finishingCompositeCollectionElement(CompositeCollectionElementDefinition compositionElementDefinition) {
|
||||
// System.out.println(
|
||||
// String.format(
|
||||
// "%s Finishing composite (%s)",
|
||||
// StringHelper.repeat( "<<", depth-- ),
|
||||
// compositionElementDefinition.getCollectionDefinition().getCollectionPersister().getRole()
|
||||
// )
|
||||
// );
|
||||
// }
|
||||
|
||||
@Override
|
||||
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition) {
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* Copyright (c) 2013, Red Hat Inc. or third-party contributors as
|
||||
* indicated by the @author tags or express copyright attribution
|
||||
* statements applied by the authors. All third-party contributions are
|
||||
* distributed under license by Red Hat Inc.
|
||||
*
|
||||
* This copyrighted material is made available to anyone wishing to use, modify,
|
||||
* copy, or redistribute it subject to the terms and conditions of the GNU
|
||||
* Lesser General Public License, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this distribution; if not, write to:
|
||||
* Free Software Foundation, Inc.
|
||||
* 51 Franklin Street, Fifth Floor
|
||||
* Boston, MA 02110-1301 USA
|
||||
*/
|
||||
package org.hibernate.test.loadplans.walking;
|
||||
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.walking.spi.MetamodelGraphWalker;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
import org.hibernate.test.loadplans.process.EncapsulatedCompositeAttributeResultSetProcessorTest.Person;
|
||||
import org.hibernate.test.loadplans.process.EncapsulatedCompositeAttributeResultSetProcessorTest.Customer;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NestedCompositeElementTest extends BaseCoreFunctionalTestCase {
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] { Person.class, Customer.class };
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWalkingKeyManyToOneGraphs() {
|
||||
final EntityPersister ep = (EntityPersister) sessionFactory().getClassMetadata( Customer.class );
|
||||
MetamodelGraphWalker.visitEntity( new LoggingAssociationVisitationStrategy(), ep );
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue