HHH-8276 - Integrate LoadPlans into UniqueEntityLoader (PoC)
This commit is contained in:
parent
438dd9c180
commit
4defc8a5d6
|
@ -36,10 +36,11 @@ import org.hibernate.loader.plan.spi.build.AbstractLoadPlanBuilderStrategy;
|
||||||
import org.hibernate.loader.plan.spi.CollectionReturn;
|
import org.hibernate.loader.plan.spi.CollectionReturn;
|
||||||
import org.hibernate.loader.plan.spi.EntityReturn;
|
import org.hibernate.loader.plan.spi.EntityReturn;
|
||||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||||
import org.hibernate.loader.plan.spi.build.LoadPlanBuilderStrategy;
|
|
||||||
import org.hibernate.loader.plan.spi.Return;
|
import org.hibernate.loader.plan.spi.Return;
|
||||||
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
|
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||||
|
|
||||||
|
@ -152,4 +153,9 @@ public class SingleRootReturnLoadPlanBuilderStrategy
|
||||||
StringHelper.unqualify( collectionRole )
|
StringHelper.unqualify( collectionRole )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FetchSource registeredFetchSource(AssociationKey associationKey) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,6 @@ import org.hibernate.loader.plan.spi.BidirectionalEntityFetch;
|
||||||
import org.hibernate.loader.plan.spi.CollectionFetch;
|
import org.hibernate.loader.plan.spi.CollectionFetch;
|
||||||
import org.hibernate.loader.plan.spi.CollectionReference;
|
import org.hibernate.loader.plan.spi.CollectionReference;
|
||||||
import org.hibernate.loader.plan.spi.CollectionReturn;
|
import org.hibernate.loader.plan.spi.CollectionReturn;
|
||||||
import org.hibernate.loader.plan.spi.CompositeElementGraph;
|
|
||||||
import org.hibernate.loader.plan.spi.CompositeFetch;
|
import org.hibernate.loader.plan.spi.CompositeFetch;
|
||||||
import org.hibernate.loader.plan.spi.CopyContext;
|
import org.hibernate.loader.plan.spi.CopyContext;
|
||||||
import org.hibernate.loader.plan.spi.EntityFetch;
|
import org.hibernate.loader.plan.spi.EntityFetch;
|
||||||
|
@ -67,7 +66,6 @@ import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
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.CompositionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||||
|
@ -427,8 +425,9 @@ public abstract class AbstractLoadPlanBuilderStrategy implements LoadPlanBuilder
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void foundCircularAssociationKey(AssociationKey associationKey, AttributeDefinition attributeDefinition) {
|
public void foundCircularAssociation(AssociationAttributeDefinition attributeDefinition) {
|
||||||
// todo : use this information to create the BiDirectionalEntityFetch instances
|
// todo : use this information to create the BiDirectionalEntityFetch instances
|
||||||
|
final AssociationKey associationKey = attributeDefinition.getAssociationKey();
|
||||||
final FetchOwner fetchOwner = fetchedAssociationKeyOwnerMap.get( associationKey );
|
final FetchOwner fetchOwner = fetchedAssociationKeyOwnerMap.get( associationKey );
|
||||||
if ( fetchOwner == null ) {
|
if ( fetchOwner == null ) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
|
|
|
@ -34,14 +34,15 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.loader.plan2.build.spi.AbstractLoadPlanBuildingAssociationVisitationStrategy;
|
import org.hibernate.loader.plan2.build.spi.AbstractLoadPlanBuildingAssociationVisitationStrategy;
|
||||||
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingAssociationVisitationStrategy;
|
import org.hibernate.loader.plan2.build.spi.ExpandingFetchSource;
|
||||||
|
import org.hibernate.loader.plan2.spi.CollectionFetch;
|
||||||
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityFetch;
|
||||||
import org.hibernate.loader.plan2.spi.EntityReturn;
|
import org.hibernate.loader.plan2.spi.EntityReturn;
|
||||||
import org.hibernate.loader.plan2.spi.LoadPlan;
|
import org.hibernate.loader.plan2.spi.LoadPlan;
|
||||||
import org.hibernate.loader.plan2.spi.Return;
|
import org.hibernate.loader.plan2.spi.Return;
|
||||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||||
import org.hibernate.persister.walking.spi.AttributeDefinition;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* LoadPlanBuilderStrategy implementation used for building LoadPlans based on metamodel-defined fetching. Built
|
* LoadPlanBuilderStrategy implementation used for building LoadPlans based on metamodel-defined fetching. Built
|
||||||
|
@ -129,11 +130,6 @@ public class FetchStyleLoadPlanBuildingAssociationVisitationStrategy
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void foundCircularAssociationKey(AssociationKey associationKey, AttributeDefinition attributeDefinition) {
|
|
||||||
// todo : implement this
|
|
||||||
}
|
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// protected EntityReturn buildRootEntityReturn(EntityDefinition entityDefinition) {
|
// protected EntityReturn buildRootEntityReturn(EntityDefinition entityDefinition) {
|
||||||
// final String entityName = entityDefinition.getEntityPersister().getEntityName();
|
// final String entityName = entityDefinition.getEntityPersister().getEntityName();
|
||||||
|
|
|
@ -23,20 +23,25 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.plan2.build.internal.returns;
|
package org.hibernate.loader.plan2.build.internal.returns;
|
||||||
|
|
||||||
|
import org.hibernate.engine.FetchStrategy;
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
import org.hibernate.loader.plan2.build.spi.ExpandingEntityIdentifierDescription;
|
import org.hibernate.loader.plan2.build.spi.ExpandingEntityIdentifierDescription;
|
||||||
|
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
||||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.EntityIdentifierDescription;
|
import org.hibernate.loader.plan2.spi.EntityFetch;
|
||||||
import org.hibernate.loader.plan2.spi.EntityReference;
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
import org.hibernate.loader.plan2.spi.FetchSource;
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
|
import org.hibernate.loader.plan2.spi.Join;
|
||||||
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
import org.hibernate.type.CompositeType;
|
import org.hibernate.type.CompositeType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
* @author Gail Badner
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCompositeEntityIdentifierDescription
|
public abstract class AbstractCompositeEntityIdentifierDescription
|
||||||
extends AbstractCompositeFetch
|
extends AbstractCompositeFetch
|
||||||
implements EntityIdentifierDescription, FetchSource, ExpandingEntityIdentifierDescription {
|
implements FetchSource, ExpandingEntityIdentifierDescription {
|
||||||
|
|
||||||
private final EntityReference entityReference;
|
private final EntityReference entityReference;
|
||||||
|
|
||||||
|
@ -57,6 +62,55 @@ public abstract class AbstractCompositeEntityIdentifierDescription
|
||||||
@Override
|
@Override
|
||||||
public FetchSource getSource() {
|
public FetchSource getSource() {
|
||||||
// the source for this (as a Fetch) is the entity reference
|
// the source for this (as a Fetch) is the entity reference
|
||||||
return (FetchSource) entityReference.getIdentifierDescription();
|
return entityReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected EntityFetch createEntityFetch(
|
||||||
|
AssociationAttributeDefinition attributeDefinition,
|
||||||
|
FetchStrategy fetchStrategy,
|
||||||
|
Join fetchedJoin,
|
||||||
|
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||||
|
// we have a key-many-to-one
|
||||||
|
//
|
||||||
|
// IMPL NOTE: we pass ourselves as the ExpandingFetchSource to collect fetches and later build
|
||||||
|
// the IdentifierDescription
|
||||||
|
|
||||||
|
// if `this` is a fetch and its owner is "the same" (bi-directionality) as the attribute to be join fetched
|
||||||
|
// we should wrap our FetchSource as an EntityFetch. That should solve everything except for the alias
|
||||||
|
// context lookups because of the different instances (because of wrapping). So somehow the consumer of this
|
||||||
|
// needs to be able to unwrap it to do the alias lookup, and would have to know to do that.
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// we are processing the EntityReference(Address) identifier. we come across its key-many-to-one reference
|
||||||
|
// to Person. Now, if EntityReference(Address) is an instance of EntityFetch(Address) there is a strong
|
||||||
|
// likelihood that we have a bi-directionality and need to handle that specially.
|
||||||
|
//
|
||||||
|
// how to best (a) find the bi-directionality and (b) represent that?
|
||||||
|
|
||||||
|
final FetchSource registeredFetchSource = loadPlanBuildingContext.registeredFetchSource(
|
||||||
|
attributeDefinition.getAssociationKey()
|
||||||
|
);
|
||||||
|
if ( isKeyManyToOneBidirectionalAttributeDefinition( attributeDefinition, loadPlanBuildingContext ) ) {
|
||||||
|
return new KeyManyToOneBidirectionalEntityFetchImpl(
|
||||||
|
this,
|
||||||
|
attributeDefinition,
|
||||||
|
fetchStrategy,
|
||||||
|
fetchedJoin,
|
||||||
|
registeredFetchSource.resolveEntityReference()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return super.createEntityFetch( attributeDefinition, fetchStrategy, fetchedJoin, loadPlanBuildingContext );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isKeyManyToOneBidirectionalAttributeDefinition(
|
||||||
|
AssociationAttributeDefinition attributeDefinition,
|
||||||
|
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||||
|
final FetchSource registeredFetchSource = loadPlanBuildingContext.registeredFetchSource(
|
||||||
|
attributeDefinition.getAssociationKey()
|
||||||
|
);
|
||||||
|
return registeredFetchSource != null && registeredFetchSource != getSource();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,7 +37,9 @@ import org.hibernate.loader.plan2.spi.CollectionFetch;
|
||||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||||
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
import org.hibernate.loader.plan2.spi.CompositeQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.EntityFetch;
|
import org.hibernate.loader.plan2.spi.EntityFetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
import org.hibernate.loader.plan2.spi.Fetch;
|
import org.hibernate.loader.plan2.spi.Fetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
import org.hibernate.loader.plan2.spi.Join;
|
import org.hibernate.loader.plan2.spi.Join;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -52,6 +54,7 @@ import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
* @author Gail Badner
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractCompositeFetch implements CompositeFetch, ExpandingFetchSource {
|
public abstract class AbstractCompositeFetch implements CompositeFetch, ExpandingFetchSource {
|
||||||
private static final FetchStrategy FETCH_STRATEGY = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
|
private static final FetchStrategy FETCH_STRATEGY = new FetchStrategy( FetchTiming.IMMEDIATE, FetchStyle.JOIN );
|
||||||
|
@ -78,6 +81,30 @@ public abstract class AbstractCompositeFetch implements CompositeFetch, Expandin
|
||||||
return compositeQuerySpace;
|
return compositeQuerySpace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityReference resolveEntityReference() {
|
||||||
|
return resolveFetchSourceEntityReference( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EntityReference resolveFetchSourceEntityReference(CompositeFetch fetch) {
|
||||||
|
final FetchSource fetchSource = fetch.getSource();
|
||||||
|
|
||||||
|
if ( EntityReference.class.isInstance( fetchSource ) ) {
|
||||||
|
return (EntityReference) fetchSource;
|
||||||
|
}
|
||||||
|
else if ( CompositeFetch.class.isInstance( fetchSource ) ) {
|
||||||
|
return resolveFetchSourceEntityReference( (CompositeFetch) fetchSource );
|
||||||
|
}
|
||||||
|
throw new IllegalStateException(
|
||||||
|
String.format(
|
||||||
|
"Cannot resolve FetchOwner [%s] of Fetch [%s (%s)] to an EntityReference",
|
||||||
|
fetchSource,
|
||||||
|
fetch,
|
||||||
|
fetch.getPropertyPath()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getQuerySpaceUid() {
|
public String getQuerySpaceUid() {
|
||||||
return compositeQuerySpace.getUid();
|
return compositeQuerySpace.getUid();
|
||||||
|
@ -117,14 +144,23 @@ public abstract class AbstractCompositeFetch implements CompositeFetch, Expandin
|
||||||
loadPlanBuildingContext.getQuerySpaces().generateImplicitUid(),
|
loadPlanBuildingContext.getQuerySpaces().generateImplicitUid(),
|
||||||
attributeDefinition.isNullable()
|
attributeDefinition.isNullable()
|
||||||
);
|
);
|
||||||
final EntityFetch fetch = new EntityFetchImpl(
|
final EntityFetch fetch = createEntityFetch( attributeDefinition, fetchStrategy, join, loadPlanBuildingContext );
|
||||||
|
addFetch( fetch );
|
||||||
|
return fetch;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected EntityFetch createEntityFetch(
|
||||||
|
AssociationAttributeDefinition attributeDefinition,
|
||||||
|
FetchStrategy fetchStrategy,
|
||||||
|
Join fetchedJoin,
|
||||||
|
LoadPlanBuildingContext loadPlanBuildingContext) {
|
||||||
|
return new EntityFetchImpl(
|
||||||
this,
|
this,
|
||||||
attributeDefinition,
|
attributeDefinition,
|
||||||
fetchStrategy,
|
fetchStrategy,
|
||||||
join
|
fetchedJoin
|
||||||
);
|
);
|
||||||
addFetch( fetch );
|
|
||||||
return fetch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addFetch(Fetch fetch) {
|
private void addFetch(Fetch fetch) {
|
||||||
|
|
|
@ -116,6 +116,11 @@ public abstract class AbstractEntityReference implements EntityReference, Expand
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityReference resolveEntityReference() {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
protected EntityQuerySpace getEntityQuerySpace() {
|
protected EntityQuerySpace getEntityQuerySpace() {
|
||||||
return entityQuerySpace;
|
return entityQuerySpace;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
package org.hibernate.loader.plan2.build.internal.returns;
|
package org.hibernate.loader.plan2.build.internal.returns;
|
||||||
|
|
||||||
import org.hibernate.loader.PropertyPath;
|
import org.hibernate.loader.PropertyPath;
|
||||||
|
import org.hibernate.loader.plan2.build.internal.spaces.CollectionQuerySpaceImpl;
|
||||||
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
||||||
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||||
|
@ -35,7 +36,7 @@ public class CollectionReturnImpl extends AbstractCollectionReference implements
|
||||||
|
|
||||||
public CollectionReturnImpl(CollectionDefinition collectionDefinition, LoadPlanBuildingContext context) {
|
public CollectionReturnImpl(CollectionDefinition collectionDefinition, LoadPlanBuildingContext context) {
|
||||||
super(
|
super(
|
||||||
context.getQuerySpaces().makeCollectionQuerySpace(
|
(CollectionQuerySpaceImpl) context.getQuerySpaces().makeCollectionQuerySpace(
|
||||||
context.getQuerySpaces().generateImplicitUid(),
|
context.getQuerySpaces().generateImplicitUid(),
|
||||||
collectionDefinition.getCollectionPersister()
|
collectionDefinition.getCollectionPersister()
|
||||||
),
|
),
|
||||||
|
|
|
@ -54,4 +54,5 @@ public class EncapsulatedEntityIdentifierDescription
|
||||||
PropertyPath propertyPath) {
|
PropertyPath propertyPath) {
|
||||||
super( entityReference, compositeQuerySpace, compositeType, propertyPath );
|
super( entityReference, compositeQuerySpace, compositeType, propertyPath );
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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.loader.plan2.build.internal.returns;
|
||||||
|
|
||||||
|
import org.hibernate.engine.FetchStrategy;
|
||||||
|
import org.hibernate.loader.plan2.build.spi.ExpandingFetchSource;
|
||||||
|
import org.hibernate.loader.plan2.spi.BidirectionalEntityFetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
|
import org.hibernate.loader.plan2.spi.Join;
|
||||||
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a key-many-to-one fetch that is bi-directionally join fetched.
|
||||||
|
* <p/>
|
||||||
|
* For example, consider an Order entity whose primary key is partially made up of the Customer entity to which
|
||||||
|
* it is associated. When we join fetch Customer -> Order(s) and then Order -> Customer we have a bi-directional
|
||||||
|
* fetch. This class would be used to represent the Order -> Customer part of that link.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public class KeyManyToOneBidirectionalEntityFetchImpl extends EntityFetchImpl implements BidirectionalEntityFetch {
|
||||||
|
private final EntityReference targetEntityReference;
|
||||||
|
|
||||||
|
public KeyManyToOneBidirectionalEntityFetchImpl(
|
||||||
|
ExpandingFetchSource fetchSource,
|
||||||
|
AssociationAttributeDefinition fetchedAttribute,
|
||||||
|
FetchStrategy fetchStrategy,
|
||||||
|
Join fetchedJoin,
|
||||||
|
EntityReference targetEntityReference) {
|
||||||
|
super( fetchSource, fetchedAttribute, fetchStrategy, fetchedJoin );
|
||||||
|
this.targetEntityReference = targetEntityReference;
|
||||||
|
}
|
||||||
|
|
||||||
|
public EntityReference getTargetEntityReference() {
|
||||||
|
return targetEntityReference;
|
||||||
|
}
|
||||||
|
}
|
|
@ -29,7 +29,6 @@ import org.hibernate.loader.plan2.build.spi.LoadPlanBuildingContext;
|
||||||
import org.hibernate.loader.plan2.spi.CollectionQuerySpace;
|
import org.hibernate.loader.plan2.spi.CollectionQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.Join;
|
import org.hibernate.loader.plan2.spi.Join;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.collection.QueryableCollection;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.PropertyMapping;
|
import org.hibernate.persister.entity.PropertyMapping;
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
|
|
|
@ -42,8 +42,8 @@ public class Helper {
|
||||||
|
|
||||||
public String[] determineRhsColumnNames(EntityType entityType, SessionFactoryImplementor sessionFactory) {
|
public String[] determineRhsColumnNames(EntityType entityType, SessionFactoryImplementor sessionFactory) {
|
||||||
final Joinable persister = entityType.getAssociatedJoinable( sessionFactory );
|
final Joinable persister = entityType.getAssociatedJoinable( sessionFactory );
|
||||||
return entityType.isReferenceToPrimaryKey()
|
return entityType.getRHSUniqueKeyPropertyName() == null ?
|
||||||
? persister.getKeyColumnNames()
|
persister.getKeyColumnNames() :
|
||||||
: ( (PropertyMapping) persister ).toColumns( entityType.getRHSUniqueKeyPropertyName() );
|
( (PropertyMapping) persister ).toColumns( entityType.getRHSUniqueKeyPropertyName() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,10 +33,10 @@ import org.jboss.logging.Logger;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.loader.plan2.build.spi.ExpandingQuerySpaces;
|
import org.hibernate.loader.plan2.build.spi.ExpandingQuerySpaces;
|
||||||
|
import org.hibernate.loader.plan2.spi.CollectionQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.EntityQuerySpace;
|
import org.hibernate.loader.plan2.spi.EntityQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpace;
|
import org.hibernate.loader.plan2.spi.QuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpaceUidNotRegisteredException;
|
import org.hibernate.loader.plan2.spi.QuerySpaceUidNotRegisteredException;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpaces;
|
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
|
||||||
|
@ -105,7 +105,7 @@ public class QuerySpacesImpl implements ExpandingQuerySpaces {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CollectionQuerySpaceImpl makeCollectionQuerySpace(String uid, CollectionPersister collectionPersister) {
|
public CollectionQuerySpace makeCollectionQuerySpace(String uid, CollectionPersister collectionPersister) {
|
||||||
if ( querySpaceByUid.containsKey( uid ) ) {
|
if ( querySpaceByUid.containsKey( uid ) ) {
|
||||||
throw new IllegalStateException( "Encountered duplicate QuerySpace uid : " + uid );
|
throw new IllegalStateException( "Encountered duplicate QuerySpace uid : " + uid );
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,7 +75,7 @@ import org.hibernate.type.Type;
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*
|
*
|
||||||
* @see org.hibernate.loader.plan.spi.build.LoadPlanBuilderStrategy
|
* @see org.hibernate.loader.plan2.build.spi.LoadPlanBuildingAssociationVisitationStrategy
|
||||||
* @see org.hibernate.persister.walking.spi.AssociationVisitationStrategy
|
* @see org.hibernate.persister.walking.spi.AssociationVisitationStrategy
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
|
@ -126,6 +126,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
if ( FetchStackAware.class.isInstance( last ) ) {
|
if ( FetchStackAware.class.isInstance( last ) ) {
|
||||||
( (FetchStackAware) last ).poppedFromStack();
|
( (FetchStackAware) last ).poppedFromStack();
|
||||||
}
|
}
|
||||||
|
|
||||||
return last;
|
return last;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -133,7 +134,6 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
return fetchSourceStack.peekFirst();
|
return fetchSourceStack.peekFirst();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// top-level AssociationVisitationStrategy hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// top-level AssociationVisitationStrategy hooks ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -163,6 +163,8 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entities ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startingEntity(EntityDefinition entityDefinition) {
|
public void startingEntity(EntityDefinition entityDefinition) {
|
||||||
log.tracef(
|
log.tracef(
|
||||||
|
@ -552,7 +554,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void associationKeyRegistered(AssociationKey associationKey) {
|
public void associationKeyRegistered(AssociationKey associationKey) {
|
||||||
// todo : use this information to maintain a map of AssociationKey->FetchOwner mappings (associationKey + current fetchOwner stack entry)
|
// todo : use this information to maintain a map of AssociationKey->FetchSource mappings (associationKey + current FetchSource stack entry)
|
||||||
// that mapping can then be used in #foundCircularAssociationKey to build the proper BiDirectionalEntityFetch
|
// that mapping can then be used in #foundCircularAssociationKey to build the proper BiDirectionalEntityFetch
|
||||||
// based on the mapped owner
|
// based on the mapped owner
|
||||||
log.tracef(
|
log.tracef(
|
||||||
|
@ -564,6 +566,32 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
fetchedAssociationKeySourceMap.put( associationKey, currentSource() );
|
fetchedAssociationKeySourceMap.put( associationKey, currentSource() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FetchSource registeredFetchSource(AssociationKey associationKey) {
|
||||||
|
return fetchedAssociationKeySourceMap.get( associationKey );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void foundCircularAssociation(AssociationAttributeDefinition attributeDefinition) {
|
||||||
|
final FetchStrategy fetchStrategy = determineFetchStrategy( attributeDefinition );
|
||||||
|
if ( fetchStrategy.getStyle() != FetchStyle.JOIN ) {
|
||||||
|
return; // nothing to do
|
||||||
|
}
|
||||||
|
|
||||||
|
// go ahead and build the bidirectional fetch
|
||||||
|
if ( attributeDefinition.getAssociationNature() == AssociationAttributeDefinition.AssociationNature.ENTITY ) {
|
||||||
|
currentSource().buildEntityFetch(
|
||||||
|
attributeDefinition,
|
||||||
|
fetchStrategy,
|
||||||
|
this
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Collection
|
||||||
|
currentSource().buildCollectionFetch( attributeDefinition, fetchStrategy, this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// @Override
|
// @Override
|
||||||
// public void foundCircularAssociationKey(AssociationKey associationKey, AttributeDefinition attributeDefinition) {
|
// public void foundCircularAssociationKey(AssociationKey associationKey, AttributeDefinition attributeDefinition) {
|
||||||
// // use this information to create the bi-directional EntityReference (as EntityFetch) instances
|
// // use this information to create the bi-directional EntityReference (as EntityFetch) instances
|
||||||
|
@ -580,7 +608,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
// final FetchSource currentFetchSource = currentSource();
|
// final FetchSource currentFetchSource = currentSource();
|
||||||
// ( (ExpandingFetchSource) currentFetchSource ).addCircularFetch( new CircularFetch( ))
|
// ( (ExpandingFetchSource) currentFetchSource ).addCircularFetch( new CircularFetch( ))
|
||||||
//
|
//
|
||||||
// currentFetchOwner().addFetch( new CircularFetch( currentSource(), fetchOwner, attributeDefinition ) );
|
// currentFetchOwner().addFetch( new CircularFetch( currentSource(), fetchSource, attributeDefinition ) );
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// public static class CircularFetch implements EntityFetch, EntityReference {
|
// public static class CircularFetch implements EntityFetch, EntityReference {
|
||||||
|
@ -658,7 +686,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// @Override
|
// @Override
|
||||||
// public Fetch makeCopy(CopyContext copyContext, FetchOwner fetchOwnerCopy) {
|
// public Fetch makeCopy(CopyContext copyContext, FetchOwner fetchSourceCopy) {
|
||||||
// // todo : will need this implemented
|
// // todo : will need this implemented
|
||||||
// return null;
|
// return null;
|
||||||
// }
|
// }
|
||||||
|
@ -696,7 +724,7 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
// 2) (because the fetch cannot be a JOIN...) do not push it to the stack
|
// 2) (because the fetch cannot be a JOIN...) do not push it to the stack
|
||||||
final FetchStrategy fetchStrategy = determineFetchStrategy( attributeDefinition );
|
final FetchStrategy fetchStrategy = determineFetchStrategy( attributeDefinition );
|
||||||
|
|
||||||
// final FetchOwner fetchOwner = currentFetchOwner();
|
// final FetchOwner fetchSource = currentFetchOwner();
|
||||||
// fetchOwner.validateFetchPlan( fetchStrategy, attributeDefinition );
|
// fetchOwner.validateFetchPlan( fetchStrategy, attributeDefinition );
|
||||||
//
|
//
|
||||||
// fetchOwner.buildAnyFetch(
|
// fetchOwner.buildAnyFetch(
|
||||||
|
@ -745,7 +773,6 @@ public abstract class AbstractLoadPlanBuildingAssociationVisitationStrategy
|
||||||
CollectionFetch fetch = currentSource.buildCollectionFetch( attributeDefinition, fetchStrategy, this );
|
CollectionFetch fetch = currentSource.buildCollectionFetch( attributeDefinition, fetchStrategy, this );
|
||||||
pushToCollectionStack( fetch );
|
pushToCollectionStack( fetch );
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.plan.spi.AbstractPlanNode;
|
import org.hibernate.loader.plan2.spi.AbstractPlanNode;
|
||||||
import org.hibernate.loader.plan2.build.internal.spaces.QuerySpacesImpl;
|
import org.hibernate.loader.plan2.build.internal.spaces.QuerySpacesImpl;
|
||||||
import org.hibernate.loader.plan2.spi.Join;
|
import org.hibernate.loader.plan2.spi.Join;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpace;
|
import org.hibernate.loader.plan2.spi.QuerySpace;
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.plan2.build.spi;
|
package org.hibernate.loader.plan2.build.spi;
|
||||||
|
|
||||||
import org.hibernate.loader.plan2.build.internal.spaces.CollectionQuerySpaceImpl;
|
import org.hibernate.loader.plan2.spi.CollectionQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.EntityQuerySpace;
|
import org.hibernate.loader.plan2.spi.EntityQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpaces;
|
import org.hibernate.loader.plan2.spi.QuerySpaces;
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
import org.hibernate.persister.collection.CollectionPersister;
|
||||||
|
@ -37,5 +37,5 @@ public interface ExpandingQuerySpaces extends QuerySpaces {
|
||||||
|
|
||||||
public EntityQuerySpace makeEntityQuerySpace(String uid, EntityPersister entityPersister);
|
public EntityQuerySpace makeEntityQuerySpace(String uid, EntityPersister entityPersister);
|
||||||
|
|
||||||
public CollectionQuerySpaceImpl makeCollectionQuerySpace(String uid, CollectionPersister collectionPersister);
|
public CollectionQuerySpace makeCollectionQuerySpace(String uid, CollectionPersister collectionPersister);
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ import org.hibernate.persister.walking.spi.AssociationVisitationStrategy;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specialized {@link org.hibernate.persister.walking.spi.AssociationVisitationStrategy} implementation for
|
* Specialized {@link org.hibernate.persister.walking.spi.AssociationVisitationStrategy} implementation for
|
||||||
* building {@link org.hibernate.loader.plan.spi.LoadPlan} instances.
|
* building {@link org.hibernate.loader.plan2.spi.LoadPlan} instances.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -24,7 +24,9 @@
|
||||||
package org.hibernate.loader.plan2.build.spi;
|
package org.hibernate.loader.plan2.build.spi;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpaces;
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
|
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides access to context needed in building a LoadPlan.
|
* Provides access to context needed in building a LoadPlan.
|
||||||
|
@ -40,4 +42,6 @@ public interface LoadPlanBuildingContext {
|
||||||
public SessionFactoryImplementor getSessionFactory();
|
public SessionFactoryImplementor getSessionFactory();
|
||||||
|
|
||||||
public ExpandingQuerySpaces getQuerySpaces();
|
public ExpandingQuerySpaces getQuerySpaces();
|
||||||
|
|
||||||
|
public FetchSource registeredFetchSource(AssociationKey associationKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import java.io.PrintWriter;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.loader.plan2.exec.internal.AliasResolutionContextImpl;
|
import org.hibernate.loader.plan2.exec.spi.AliasResolutionContext;
|
||||||
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
||||||
import org.hibernate.loader.plan2.spi.EntityReturn;
|
import org.hibernate.loader.plan2.spi.EntityReturn;
|
||||||
import org.hibernate.loader.plan2.spi.LoadPlan;
|
import org.hibernate.loader.plan2.spi.LoadPlan;
|
||||||
|
@ -57,7 +57,7 @@ public class LoadPlanTreePrinter {
|
||||||
return toString( loadPlan, null );
|
return toString( loadPlan, null );
|
||||||
}
|
}
|
||||||
|
|
||||||
private String toString(LoadPlan loadPlan, AliasResolutionContextImpl aliasResolutionContext) {
|
private String toString(LoadPlan loadPlan, AliasResolutionContext aliasResolutionContext) {
|
||||||
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||||
final PrintStream printStream = new PrintStream( byteArrayOutputStream );
|
final PrintStream printStream = new PrintStream( byteArrayOutputStream );
|
||||||
final PrintWriter printWriter = new PrintWriter( printStream );
|
final PrintWriter printWriter = new PrintWriter( printStream );
|
||||||
|
@ -70,7 +70,7 @@ public class LoadPlanTreePrinter {
|
||||||
return new String( byteArrayOutputStream.toByteArray() );
|
return new String( byteArrayOutputStream.toByteArray() );
|
||||||
}
|
}
|
||||||
|
|
||||||
public void logTree(LoadPlan loadPlan, AliasResolutionContextImpl aliasResolutionContext) {
|
public void logTree(LoadPlan loadPlan, AliasResolutionContext aliasResolutionContext) {
|
||||||
if ( ! log.isDebugEnabled() ) {
|
if ( ! log.isDebugEnabled() ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ public class LoadPlanTreePrinter {
|
||||||
|
|
||||||
private void logTree(
|
private void logTree(
|
||||||
LoadPlan loadPlan,
|
LoadPlan loadPlan,
|
||||||
AliasResolutionContextImpl aliasResolutionContext,
|
AliasResolutionContext aliasResolutionContext,
|
||||||
PrintWriter printWriter) {
|
PrintWriter printWriter) {
|
||||||
printWriter.println( "LoadPlan(" + extractDetails( loadPlan ) + ")" );
|
printWriter.println( "LoadPlan(" + extractDetails( loadPlan ) + ")" );
|
||||||
printWriter.println( TreePrinterHelper.INSTANCE.generateNodePrefix( 1 ) + "Returns" );
|
printWriter.println( TreePrinterHelper.INSTANCE.generateNodePrefix( 1 ) + "Returns" );
|
||||||
|
|
|
@ -29,7 +29,6 @@ import java.io.PrintWriter;
|
||||||
|
|
||||||
import org.hibernate.internal.util.StringHelper;
|
import org.hibernate.internal.util.StringHelper;
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
import org.hibernate.loader.plan2.build.internal.spaces.CollectionQuerySpaceImpl;
|
|
||||||
import org.hibernate.loader.plan2.exec.spi.AliasResolutionContext;
|
import org.hibernate.loader.plan2.exec.spi.AliasResolutionContext;
|
||||||
import org.hibernate.loader.plan2.exec.spi.CollectionReferenceAliases;
|
import org.hibernate.loader.plan2.exec.spi.CollectionReferenceAliases;
|
||||||
import org.hibernate.loader.plan2.exec.spi.EntityReferenceAliases;
|
import org.hibernate.loader.plan2.exec.spi.EntityReferenceAliases;
|
||||||
|
|
|
@ -88,7 +88,7 @@ public class AliasResolutionContextImpl implements AliasResolutionContext {
|
||||||
* non-query (HQL, criteria, etc) contexts.
|
* non-query (HQL, criteria, etc) contexts.
|
||||||
* <p/>
|
* <p/>
|
||||||
* See the notes on
|
* See the notes on
|
||||||
* {@link org.hibernate.loader.plan.exec.spi.AliasResolutionContext#getSourceAlias} for discussion of
|
* {@link org.hibernate.loader.plan2.exec.spi.AliasResolutionContext#getSourceAlias} for discussion of
|
||||||
* "source aliases". They are not implemented here yet.
|
* "source aliases". They are not implemented here yet.
|
||||||
*
|
*
|
||||||
* @param sessionFactory The session factory
|
* @param sessionFactory The session factory
|
||||||
|
|
|
@ -140,7 +140,7 @@ public class CollectionReferenceInitializerImpl implements CollectionReferenceIn
|
||||||
collectionRowKey,
|
collectionRowKey,
|
||||||
collectionReference.getCollectionPersister()
|
collectionReference.getCollectionPersister()
|
||||||
);
|
);
|
||||||
// todo : try org.hibernate.loader.plan.exec.process.spi.ResultSetProcessingContext.getOwnerProcessingState() ??
|
// todo : try org.hibernate.loader.plan2.exec.process.spi.ResultSetProcessingContext.getOwnerProcessingState() ??
|
||||||
// -- specifically to return its ResultSetProcessingContext.EntityReferenceProcessingState#getEntityInstance()
|
// -- specifically to return its ResultSetProcessingContext.EntityReferenceProcessingState#getEntityInstance()
|
||||||
if ( collectionOwner == null ) {
|
if ( collectionOwner == null ) {
|
||||||
//TODO: This is assertion is disabled because there is a bug that means the
|
//TODO: This is assertion is disabled because there is a bug that means the
|
||||||
|
|
|
@ -79,27 +79,16 @@ public class EntityReferenceInitializerImpl implements EntityReferenceInitialize
|
||||||
isReturn = isRoot;
|
isReturn = isRoot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public EntityReference getEntityReference() {
|
||||||
|
return entityReference;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void hydrateIdentifier(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException {
|
public void hydrateIdentifier(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException {
|
||||||
|
|
||||||
final EntityReferenceProcessingState processingState = context.getProcessingState( entityReference );
|
final EntityReferenceProcessingState processingState = context.getProcessingState( entityReference );
|
||||||
|
|
||||||
// if the entity reference we are hydrating is a Return, it is possible that its EntityKey is
|
|
||||||
// supplied by the QueryParameter optional entity information
|
|
||||||
if ( context.shouldUseOptionalEntityInformation() ) {
|
|
||||||
if ( isReturn ) {
|
|
||||||
final EntityKey entityKey = ResultSetProcessorHelper.getOptionalObjectKey(
|
|
||||||
context.getQueryParameters(),
|
|
||||||
context.getSession()
|
|
||||||
);
|
|
||||||
|
|
||||||
if ( entityKey != null ) {
|
|
||||||
processingState.registerEntityKey( entityKey );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// get any previously registered identifier hydrated-state
|
// get any previously registered identifier hydrated-state
|
||||||
Object identifierHydratedForm = processingState.getIdentifierHydratedForm();
|
Object identifierHydratedForm = processingState.getIdentifierHydratedForm();
|
||||||
if ( identifierHydratedForm == null ) {
|
if ( identifierHydratedForm == null ) {
|
||||||
|
@ -144,7 +133,6 @@ public class EntityReferenceInitializerImpl implements EntityReferenceInitialize
|
||||||
@Override
|
@Override
|
||||||
public void resolveEntityKey(ResultSet resultSet, ResultSetProcessingContextImpl context) {
|
public void resolveEntityKey(ResultSet resultSet, ResultSetProcessingContextImpl context) {
|
||||||
|
|
||||||
|
|
||||||
final EntityReferenceProcessingState processingState = context.getProcessingState( entityReference );
|
final EntityReferenceProcessingState processingState = context.getProcessingState( entityReference );
|
||||||
|
|
||||||
// see if we already have an EntityKey associated with this EntityReference in the processing state.
|
// see if we already have an EntityKey associated with this EntityReference in the processing state.
|
||||||
|
|
|
@ -48,7 +48,7 @@ public class EntityReturnReader implements ReturnReader {
|
||||||
this.aliases = aliases;
|
this.aliases = aliases;
|
||||||
}
|
}
|
||||||
|
|
||||||
private EntityReferenceProcessingState getIdentifierResolutionContext(ResultSetProcessingContext context) {
|
public EntityReferenceProcessingState getIdentifierResolutionContext(ResultSetProcessingContext context) {
|
||||||
final EntityReferenceProcessingState entityReferenceProcessingState = context.getProcessingState( entityReturn );
|
final EntityReferenceProcessingState entityReferenceProcessingState = context.getProcessingState( entityReturn );
|
||||||
|
|
||||||
if ( entityReferenceProcessingState == null ) {
|
if ( entityReferenceProcessingState == null ) {
|
||||||
|
|
|
@ -35,29 +35,18 @@ import java.util.Set;
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
import org.hibernate.LockMode;
|
import org.hibernate.LockMode;
|
||||||
import org.hibernate.engine.internal.TwoPhaseLoad;
|
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.QueryParameters;
|
import org.hibernate.engine.spi.QueryParameters;
|
||||||
import org.hibernate.engine.spi.SessionImplementor;
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.engine.spi.SubselectFetch;
|
import org.hibernate.engine.spi.SubselectFetch;
|
||||||
import org.hibernate.event.spi.EventSource;
|
|
||||||
import org.hibernate.event.spi.PostLoadEvent;
|
|
||||||
import org.hibernate.event.spi.PreLoadEvent;
|
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.ResultSetProcessingContext;
|
import org.hibernate.loader.plan2.exec.process.spi.ResultSetProcessingContext;
|
||||||
import org.hibernate.loader.plan2.exec.query.spi.NamedParameterContext;
|
import org.hibernate.loader.plan2.exec.query.spi.NamedParameterContext;
|
||||||
import org.hibernate.loader.plan2.exec.spi.LockModeResolver;
|
|
||||||
import org.hibernate.loader.plan2.spi.CollectionFetch;
|
|
||||||
import org.hibernate.loader.plan2.spi.CollectionReturn;
|
|
||||||
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||||
import org.hibernate.loader.plan2.spi.EntityFetch;
|
import org.hibernate.loader.plan2.spi.EntityFetch;
|
||||||
import org.hibernate.loader.plan2.spi.EntityReference;
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
import org.hibernate.loader.plan2.spi.Fetch;
|
import org.hibernate.loader.plan2.spi.Fetch;
|
||||||
import org.hibernate.loader.plan2.spi.FetchSource;
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
import org.hibernate.loader.plan2.spi.LoadPlan;
|
import org.hibernate.loader.plan2.spi.LoadPlan;
|
||||||
import org.hibernate.loader.plan.spi.visit.LoadPlanVisitationStrategyAdapter;
|
|
||||||
import org.hibernate.loader.plan.spi.visit.LoadPlanVisitor;
|
|
||||||
import org.hibernate.loader.spi.AfterLoadAction;
|
|
||||||
import org.hibernate.persister.collection.CollectionPersister;
|
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
import org.hibernate.type.EntityType;
|
import org.hibernate.type.EntityType;
|
||||||
|
@ -276,27 +265,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EntityReferenceProcessingState getOwnerProcessingState(Fetch fetch) {
|
public EntityReferenceProcessingState getOwnerProcessingState(Fetch fetch) {
|
||||||
return getProcessingState( resolveFetchOwnerEntityReference( fetch ) );
|
return getProcessingState( fetch.getSource().resolveEntityReference() );
|
||||||
}
|
|
||||||
|
|
||||||
private EntityReference resolveFetchOwnerEntityReference(Fetch fetch) {
|
|
||||||
final FetchSource fetchSource = fetch.getSource();
|
|
||||||
|
|
||||||
if ( EntityReference.class.isInstance( fetchSource ) ) {
|
|
||||||
return (EntityReference) fetchSource;
|
|
||||||
}
|
|
||||||
else if ( CompositeFetch.class.isInstance( fetchSource ) ) {
|
|
||||||
return resolveFetchOwnerEntityReference( (CompositeFetch) fetchSource );
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalStateException(
|
|
||||||
String.format(
|
|
||||||
"Cannot resolve FetchOwner [%s] of Fetch [%s (%s)] to an EntityReference",
|
|
||||||
fetchSource,
|
|
||||||
fetch,
|
|
||||||
fetch.getPropertyPath()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -64,10 +64,10 @@ public class ResultSetProcessorHelper {
|
||||||
else {
|
else {
|
||||||
entityPersister = session.getFactory().getEntityPersister( optionalEntityName );
|
entityPersister = session.getFactory().getEntityPersister( optionalEntityName );
|
||||||
}
|
}
|
||||||
if ( entityPersister.isInstance( optionalId ) && !entityPersister.getEntityMetamodel()
|
if ( entityPersister.isInstance( optionalId ) &&
|
||||||
.getIdentifierProperty()
|
!entityPersister.getEntityMetamodel().getIdentifierProperty().isVirtual() &&
|
||||||
.isVirtual() && entityPersister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
|
entityPersister.getEntityMetamodel().getIdentifierProperty().isEmbedded() ) {
|
||||||
// embedded (non-encapsulated) composite identifier
|
// non-encapsulated composite identifier
|
||||||
final Serializable identifierState = ((CompositeType) entityPersister.getIdentifierType()).getPropertyValues(
|
final Serializable identifierState = ((CompositeType) entityPersister.getIdentifierType()).getPropertyValues(
|
||||||
optionalId,
|
optionalId,
|
||||||
session
|
session
|
||||||
|
|
|
@ -25,7 +25,9 @@ package org.hibernate.loader.plan2.exec.process.spi;
|
||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
@ -37,6 +39,13 @@ import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.HydratedEntityRegistration;
|
import org.hibernate.loader.plan2.exec.process.internal.HydratedEntityRegistration;
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl;
|
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl;
|
||||||
|
import org.hibernate.loader.plan2.spi.BidirectionalEntityFetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.CompositeFetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityFetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityIdentifierDescription;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
|
import org.hibernate.loader.plan2.spi.Fetch;
|
||||||
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
import org.hibernate.loader.spi.AfterLoadAction;
|
import org.hibernate.loader.spi.AfterLoadAction;
|
||||||
import org.hibernate.persister.entity.Loadable;
|
import org.hibernate.persister.entity.Loadable;
|
||||||
|
|
||||||
|
@ -66,8 +75,18 @@ public abstract class AbstractRowReader implements RowReader {
|
||||||
for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) {
|
for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) {
|
||||||
entityReferenceInitializer.hydrateIdentifier( resultSet, context );
|
entityReferenceInitializer.hydrateIdentifier( resultSet, context );
|
||||||
}
|
}
|
||||||
|
final Map<EntityReference,EntityReferenceInitializer> initializerByEntityReference =
|
||||||
|
new HashMap<EntityReference, EntityReferenceInitializer>( entityReferenceInitializers.size() );
|
||||||
|
for ( EntityReferenceInitializer entityReferenceInitializerFromMap : entityReferenceInitializers ) {
|
||||||
|
initializerByEntityReference.put( entityReferenceInitializerFromMap.getEntityReference(), entityReferenceInitializerFromMap );
|
||||||
|
}
|
||||||
for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) {
|
for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) {
|
||||||
entityReferenceInitializer.resolveEntityKey( resultSet, context );
|
resolveEntityKey(
|
||||||
|
resultSet,
|
||||||
|
context,
|
||||||
|
entityReferenceInitializer,
|
||||||
|
initializerByEntityReference
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2) allow entity references to resolve their non-identifier hydrated state and entity instance
|
// 2) allow entity references to resolve their non-identifier hydrated state and entity instance
|
||||||
|
@ -102,6 +121,58 @@ public abstract class AbstractRowReader implements RowReader {
|
||||||
return logicalRow;
|
return logicalRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void resolveEntityKey(
|
||||||
|
ResultSet resultSet,
|
||||||
|
ResultSetProcessingContextImpl context,
|
||||||
|
EntityReferenceInitializer entityReferenceInitializer,
|
||||||
|
Map<EntityReference,EntityReferenceInitializer> initializerByEntityReference) throws SQLException {
|
||||||
|
final EntityReference entityReference = entityReferenceInitializer.getEntityReference();
|
||||||
|
final EntityIdentifierDescription identifierDescription = entityReference.getIdentifierDescription();
|
||||||
|
|
||||||
|
if ( identifierDescription.hasFetches() ) {
|
||||||
|
resolveEntityKey( resultSet, context, (FetchSource) identifierDescription, initializerByEntityReference );
|
||||||
|
}
|
||||||
|
entityReferenceInitializer.resolveEntityKey( resultSet, context );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resolveEntityKey(
|
||||||
|
ResultSet resultSet,
|
||||||
|
ResultSetProcessingContextImpl context,
|
||||||
|
FetchSource fetchSource,
|
||||||
|
Map<EntityReference,EntityReferenceInitializer> initializerByEntityReference) throws SQLException {
|
||||||
|
for ( Fetch fetch : fetchSource.getFetches() ) {
|
||||||
|
if ( EntityFetch.class.isInstance( fetch ) ) {
|
||||||
|
final EntityFetch entityFetch = (EntityFetch) fetch;
|
||||||
|
final EntityReferenceInitializer targetEntityReferenceInitializer;
|
||||||
|
if ( BidirectionalEntityFetch.class.isInstance( fetch ) ) {
|
||||||
|
final BidirectionalEntityFetch bidirectionalEntityFetch = (BidirectionalEntityFetch) fetch;
|
||||||
|
targetEntityReferenceInitializer = initializerByEntityReference.get(
|
||||||
|
bidirectionalEntityFetch.getTargetEntityReference()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
targetEntityReferenceInitializer = initializerByEntityReference.get( entityFetch );
|
||||||
|
}
|
||||||
|
if ( targetEntityReferenceInitializer != null ) {
|
||||||
|
resolveEntityKey(
|
||||||
|
resultSet,
|
||||||
|
context,
|
||||||
|
targetEntityReferenceInitializer,
|
||||||
|
initializerByEntityReference
|
||||||
|
);
|
||||||
|
targetEntityReferenceInitializer.hydrateEntityState( resultSet, context );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( CompositeFetch.class.isInstance( fetch ) ) {
|
||||||
|
resolveEntityKey(
|
||||||
|
resultSet,
|
||||||
|
context,
|
||||||
|
(CompositeFetch) fetch,
|
||||||
|
initializerByEntityReference );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishUp(ResultSetProcessingContextImpl context, List<AfterLoadAction> afterLoadActionList) {
|
public void finishUp(ResultSetProcessingContextImpl context, List<AfterLoadAction> afterLoadActionList) {
|
||||||
final List<HydratedEntityRegistration> hydratedEntityRegistrations = context.getHydratedEntityRegistrationList();
|
final List<HydratedEntityRegistration> hydratedEntityRegistrations = context.getHydratedEntityRegistrationList();
|
||||||
|
|
|
@ -27,11 +27,14 @@ import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
|
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl;
|
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl;
|
||||||
|
import org.hibernate.loader.plan2.spi.EntityReference;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public interface EntityReferenceInitializer {
|
public interface EntityReferenceInitializer {
|
||||||
|
EntityReference getEntityReference();
|
||||||
|
|
||||||
void hydrateIdentifier(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException;
|
void hydrateIdentifier(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException;
|
||||||
|
|
||||||
void resolveEntityKey(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException;
|
void resolveEntityKey(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException;
|
||||||
|
|
|
@ -31,6 +31,9 @@ import java.util.List;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import org.hibernate.LockOptions;
|
||||||
|
import org.hibernate.Session;
|
||||||
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
import org.hibernate.internal.CoreLogging;
|
import org.hibernate.internal.CoreLogging;
|
||||||
import org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter;
|
import org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter;
|
||||||
|
@ -41,11 +44,13 @@ import org.hibernate.loader.plan2.exec.internal.LoadQueryJoinAndFetchProcessor;
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.EntityReferenceInitializerImpl;
|
import org.hibernate.loader.plan2.exec.process.internal.EntityReferenceInitializerImpl;
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.EntityReturnReader;
|
import org.hibernate.loader.plan2.exec.process.internal.EntityReturnReader;
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl;
|
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessingContextImpl;
|
||||||
|
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessorHelper;
|
||||||
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessorImpl;
|
import org.hibernate.loader.plan2.exec.process.internal.ResultSetProcessorImpl;
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.AbstractRowReader;
|
import org.hibernate.loader.plan2.exec.process.spi.AbstractRowReader;
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.CollectionReferenceInitializer;
|
import org.hibernate.loader.plan2.exec.process.spi.CollectionReferenceInitializer;
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.EntityReferenceInitializer;
|
import org.hibernate.loader.plan2.exec.process.spi.EntityReferenceInitializer;
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.ReaderCollector;
|
import org.hibernate.loader.plan2.exec.process.spi.ReaderCollector;
|
||||||
|
import org.hibernate.loader.plan2.exec.process.spi.ResultSetProcessingContext;
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.ResultSetProcessor;
|
import org.hibernate.loader.plan2.exec.process.spi.ResultSetProcessor;
|
||||||
import org.hibernate.loader.plan2.exec.process.spi.RowReader;
|
import org.hibernate.loader.plan2.exec.process.spi.RowReader;
|
||||||
import org.hibernate.loader.plan2.exec.query.internal.SelectStatementBuilder;
|
import org.hibernate.loader.plan2.exec.query.internal.SelectStatementBuilder;
|
||||||
|
@ -54,11 +59,14 @@ import org.hibernate.loader.plan2.spi.EntityQuerySpace;
|
||||||
import org.hibernate.loader.plan2.spi.EntityReturn;
|
import org.hibernate.loader.plan2.spi.EntityReturn;
|
||||||
import org.hibernate.loader.plan2.spi.LoadPlan;
|
import org.hibernate.loader.plan2.spi.LoadPlan;
|
||||||
import org.hibernate.loader.plan2.spi.QuerySpaces;
|
import org.hibernate.loader.plan2.spi.QuerySpaces;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||||
import org.hibernate.persister.entity.Queryable;
|
import org.hibernate.persister.entity.Queryable;
|
||||||
import org.hibernate.sql.ConditionFragment;
|
import org.hibernate.sql.ConditionFragment;
|
||||||
import org.hibernate.sql.DisjunctionFragment;
|
import org.hibernate.sql.DisjunctionFragment;
|
||||||
import org.hibernate.sql.InFragment;
|
import org.hibernate.sql.InFragment;
|
||||||
|
import org.hibernate.type.ComponentType;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles interpreting a LoadPlan (for loading of an entity) by:<ul>
|
* Handles interpreting a LoadPlan (for loading of an entity) by:<ul>
|
||||||
|
@ -410,6 +418,47 @@ public class EntityLoadQueryDetails implements LoadQueryDetails {
|
||||||
: Collections.<CollectionReferenceInitializer>emptyList();
|
: Collections.<CollectionReferenceInitializer>emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Object readRow(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException {
|
||||||
|
final ResultSetProcessingContext.EntityReferenceProcessingState processingState =
|
||||||
|
rootReturnReader.getIdentifierResolutionContext( context );
|
||||||
|
// if the entity reference we are hydrating is a Return, it is possible that its EntityKey is
|
||||||
|
// supplied by the QueryParameter optional entity information
|
||||||
|
if ( context.shouldUseOptionalEntityInformation() && context.getQueryParameters().getOptionalId() != null ) {
|
||||||
|
EntityKey entityKey = ResultSetProcessorHelper.getOptionalObjectKey(
|
||||||
|
context.getQueryParameters(),
|
||||||
|
context.getSession()
|
||||||
|
);
|
||||||
|
processingState.registerIdentifierHydratedForm( entityKey.getIdentifier() );
|
||||||
|
processingState.registerEntityKey( entityKey );
|
||||||
|
final EntityPersister entityPersister = processingState.getEntityReference().getEntityPersister();
|
||||||
|
if ( entityPersister.getIdentifierType().isComponentType() ) {
|
||||||
|
final ComponentType identifierType = (ComponentType) entityPersister.getIdentifierType();
|
||||||
|
if ( !identifierType.isEmbedded() ) {
|
||||||
|
addKeyManyToOnesToSession(
|
||||||
|
context,
|
||||||
|
identifierType,
|
||||||
|
entityKey.getIdentifier()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return super.readRow( resultSet, context );
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addKeyManyToOnesToSession(ResultSetProcessingContextImpl context, ComponentType componentType, Object component ) {
|
||||||
|
for ( int i = 0 ; i < componentType.getSubtypes().length ; i++ ) {
|
||||||
|
final Type subType = componentType.getSubtypes()[ i ];
|
||||||
|
final Object subValue = componentType.getPropertyValue( component, i, context.getSession() );
|
||||||
|
if ( subType.isEntityType() ) {
|
||||||
|
( (Session) context.getSession() ).buildLockRequest( LockOptions.NONE ).lock( subValue );
|
||||||
|
}
|
||||||
|
else if ( subType.isComponentType() ) {
|
||||||
|
addKeyManyToOnesToSession( context, (ComponentType) subType, subValue );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected List<EntityReferenceInitializer> getEntityReferenceInitializers() {
|
protected List<EntityReferenceInitializer> getEntityReferenceInitializers() {
|
||||||
return entityReferenceInitializers;
|
return entityReferenceInitializers;
|
||||||
|
|
|
@ -26,7 +26,7 @@ package org.hibernate.loader.plan2.exec.spi;
|
||||||
import org.hibernate.loader.EntityAliases;
|
import org.hibernate.loader.EntityAliases;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Aggregates the alias/suffix information in relation to an {@link org.hibernate.loader.plan.spi.EntityReference}
|
* Aggregates the alias/suffix information in relation to an {@link org.hibernate.loader.plan2.spi.EntityReference}
|
||||||
*
|
*
|
||||||
* todo : add a contract (interface) that can be shared by entity and collection alias info objects as lhs/rhs of a join ?
|
* todo : add a contract (interface) that can be shared by entity and collection alias info objects as lhs/rhs of a join ?
|
||||||
*
|
*
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
/*
|
||||||
|
* 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.loader.plan2.spi;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the circular side of a bi-directional entity fetch. Wraps a reference to an EntityReference
|
||||||
|
* as an EntityFetch. We can use the special type as a trigger in AliasResolutionContext, etc to lookup information
|
||||||
|
* based on the wrapped reference.
|
||||||
|
* <p/>
|
||||||
|
* This relies on reference lookups against the EntityReference instances, therefore this allows representation of the
|
||||||
|
* circularity but with a little protection against potential stack overflows. This is unfortunately still a cyclic
|
||||||
|
* graph. An alternative approach is to make the graph acyclic (DAG) would be to follow the process I adopted in the
|
||||||
|
* original HQL Antlr v3 work with regard to always applying an alias to the "persister reference", even where that
|
||||||
|
* meant creating a generated, unique identifier as the alias. That allows other parts of the tree to refer to the
|
||||||
|
* "persister reference" by that alias without the need for potentially cyclic graphs (think ALIAS_REF in the current
|
||||||
|
* ORM parser). Those aliases can then be mapped/catalogued against the "persister reference" for retrieval as needed.
|
||||||
|
*
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
public interface BidirectionalEntityFetch {
|
||||||
|
/**
|
||||||
|
* Get the targeted EntityReference
|
||||||
|
*
|
||||||
|
* @return The targeted EntityReference
|
||||||
|
*/
|
||||||
|
public EntityReference getTargetEntityReference();
|
||||||
|
}
|
|
@ -53,7 +53,22 @@ public interface FetchSource {
|
||||||
*/
|
*/
|
||||||
public Fetch[] getFetches();
|
public Fetch[] getFetches();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resolve the "current" {@link EntityReference}, or null if none.
|
||||||
|
*
|
||||||
|
* If this object is an {@link EntityReference}, then this object is returned.
|
||||||
|
*
|
||||||
|
* If this object is a {@link CompositeFetch}, then the nearest {@link EntityReference}
|
||||||
|
* will be resolved from its source, if possible.
|
||||||
|
*
|
||||||
|
* If no EntityReference can be resolved, null is return.
|
||||||
|
*
|
||||||
|
* @return the "current" EntityReference or null if none.
|
||||||
|
* otherwise, if this object is also a {@link Fetch}, then
|
||||||
|
* .
|
||||||
|
* @see org.hibernate.loader.plan2.spi.Fetch#getSource().
|
||||||
|
* */
|
||||||
|
public EntityReference resolveEntityReference();
|
||||||
|
|
||||||
// Stuff I can hopefully remove ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
// Stuff I can hopefully remove ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
|
|
@ -31,17 +31,17 @@ import java.util.List;
|
||||||
* Generally speaking there are 3 forms of load plans:<ul>
|
* Generally speaking there are 3 forms of load plans:<ul>
|
||||||
* <li>
|
* <li>
|
||||||
* {@link org.hibernate.loader.plan2.spi.LoadPlan.Disposition#ENTITY_LOADER} - An entity load plan for
|
* {@link org.hibernate.loader.plan2.spi.LoadPlan.Disposition#ENTITY_LOADER} - An entity load plan for
|
||||||
* handling get/load handling. This form will typically have a single return (of type {@link org.hibernate.loader.plan.spi.EntityReturn})
|
* handling get/load handling. This form will typically have a single return (of type {@link org.hibernate.loader.plan2.spi.EntityReturn})
|
||||||
* defined by {@link #getReturns()}, possibly defining fetches.
|
* defined by {@link #getReturns()}, possibly defining fetches.
|
||||||
* </li>
|
* </li>
|
||||||
* <li>
|
* <li>
|
||||||
* {@link org.hibernate.loader.plan2.spi.LoadPlan.Disposition#COLLECTION_INITIALIZER} - A collection initializer,
|
* {@link org.hibernate.loader.plan2.spi.LoadPlan.Disposition#COLLECTION_INITIALIZER} - A collection initializer,
|
||||||
* used to load the contents of a collection. This form will typically have a single return (of
|
* used to load the contents of a collection. This form will typically have a single return (of
|
||||||
* type {@link org.hibernate.loader.plan.spi.CollectionReturn}) defined by {@link #getReturns()}, possibly defining fetches
|
* type {@link org.hibernate.loader.plan2.spi.CollectionReturn}) defined by {@link #getReturns()}, possibly defining fetches
|
||||||
* </li>
|
* </li>
|
||||||
* <li>
|
* <li>
|
||||||
* {@link org.hibernate.loader.plan2.spi.LoadPlan.Disposition#MIXED} - A query load plan which can contain
|
* {@link org.hibernate.loader.plan2.spi.LoadPlan.Disposition#MIXED} - A query load plan which can contain
|
||||||
* multiple returns of mixed type (though all implementing {@link org.hibernate.loader.plan.spi.Return}). Again, may possibly define fetches.
|
* multiple returns of mixed type (though all implementing {@link org.hibernate.loader.plan2.spi.Return}). Again, may possibly define fetches.
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
* <p/>
|
* <p/>
|
||||||
|
@ -64,15 +64,15 @@ public interface LoadPlan {
|
||||||
/**
|
/**
|
||||||
* Get the returns indicated by this LoadPlan.<ul>
|
* Get the returns indicated by this LoadPlan.<ul>
|
||||||
* <li>
|
* <li>
|
||||||
* A {@link Disposition#ENTITY_LOADER} LoadPlan would have just a single Return of type {@link org.hibernate.loader.plan.spi.EntityReturn}.
|
* A {@link Disposition#ENTITY_LOADER} LoadPlan would have just a single Return of type {@link org.hibernate.loader.plan2.spi.EntityReturn}.
|
||||||
* </li>
|
* </li>
|
||||||
* <li>
|
* <li>
|
||||||
* A {@link Disposition#COLLECTION_INITIALIZER} LoadPlan would have just a single Return of type
|
* A {@link Disposition#COLLECTION_INITIALIZER} LoadPlan would have just a single Return of type
|
||||||
* {@link org.hibernate.loader.plan.spi.CollectionReturn}.
|
* {@link org.hibernate.loader.plan2.spi.CollectionReturn}.
|
||||||
* </li>
|
* </li>
|
||||||
* <li>
|
* <li>
|
||||||
* A {@link Disposition#MIXED} LoadPlan would contain a mix of {@link org.hibernate.loader.plan.spi.EntityReturn} and
|
* A {@link Disposition#MIXED} LoadPlan would contain a mix of {@link org.hibernate.loader.plan2.spi.EntityReturn} and
|
||||||
* {@link org.hibernate.loader.plan.spi.ScalarReturn} elements, but no {@link org.hibernate.loader.plan.spi.CollectionReturn}.
|
* {@link org.hibernate.loader.plan2.spi.ScalarReturn} elements, but no {@link org.hibernate.loader.plan2.spi.CollectionReturn}.
|
||||||
* </li>
|
* </li>
|
||||||
* </ul>
|
* </ul>
|
||||||
*
|
*
|
||||||
|
@ -122,17 +122,17 @@ public interface LoadPlan {
|
||||||
public static enum Disposition {
|
public static enum Disposition {
|
||||||
/**
|
/**
|
||||||
* This is an "entity loader" load plan, which describes a plan for loading one or more entity instances of
|
* This is an "entity loader" load plan, which describes a plan for loading one or more entity instances of
|
||||||
* the same entity type. There is a single return, which will be of type {@link org.hibernate.loader.plan.spi.EntityReturn}
|
* the same entity type. There is a single return, which will be of type {@link org.hibernate.loader.plan2.spi.EntityReturn}
|
||||||
*/
|
*/
|
||||||
ENTITY_LOADER,
|
ENTITY_LOADER,
|
||||||
/**
|
/**
|
||||||
* This is a "collection initializer" load plan, which describes a plan for loading one or more entity instances of
|
* This is a "collection initializer" load plan, which describes a plan for loading one or more entity instances of
|
||||||
* the same collection type. There is a single return, which will be of type {@link org.hibernate.loader.plan.spi.CollectionReturn}
|
* the same collection type. There is a single return, which will be of type {@link org.hibernate.loader.plan2.spi.CollectionReturn}
|
||||||
*/
|
*/
|
||||||
COLLECTION_INITIALIZER,
|
COLLECTION_INITIALIZER,
|
||||||
/**
|
/**
|
||||||
* We have a mixed load plan, which will have one or more returns of {@link org.hibernate.loader.plan.spi.EntityReturn} and {@link org.hibernate.loader.plan.spi.ScalarReturn}
|
* We have a mixed load plan, which will have one or more returns of {@link org.hibernate.loader.plan2.spi.EntityReturn} and {@link org.hibernate.loader.plan2.spi.ScalarReturn}
|
||||||
* (NOT {@link org.hibernate.loader.plan.spi.CollectionReturn}).
|
* (NOT {@link org.hibernate.loader.plan2.spi.CollectionReturn}).
|
||||||
*/
|
*/
|
||||||
MIXED
|
MIXED
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ package org.hibernate.loader.plan2.spi;
|
||||||
/**
|
/**
|
||||||
* Represents a return value in the query results. Not the same as a result (column) in the JDBC ResultSet!
|
* Represents a return value in the query results. Not the same as a result (column) in the JDBC ResultSet!
|
||||||
* <p/>
|
* <p/>
|
||||||
* Return is distinctly different from a {@link org.hibernate.loader.plan.spi.Fetch} and so modeled as completely separate hierarchy.
|
* Return is distinctly different from a {@link org.hibernate.loader.plan2.spi.Fetch} and so modeled as completely separate hierarchy.
|
||||||
*
|
*
|
||||||
* @see ScalarReturn
|
* @see ScalarReturn
|
||||||
* @see EntityReturn
|
* @see EntityReturn
|
||||||
|
|
|
@ -23,6 +23,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.persister.walking.spi;
|
package org.hibernate.persister.walking.spi;
|
||||||
|
|
||||||
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Strategy for walking associations as defined by the Hibernate metamodel. Is essentially a callback listener for
|
* Strategy for walking associations as defined by the Hibernate metamodel. Is essentially a callback listener for
|
||||||
* interesting events while walking a metamodel graph
|
* interesting events while walking a metamodel graph
|
||||||
|
@ -166,5 +168,6 @@ public interface AssociationVisitationStrategy {
|
||||||
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition);
|
public void foundAny(AssociationAttributeDefinition attributeDefinition, AnyMappingDefinition anyDefinition);
|
||||||
|
|
||||||
public void associationKeyRegistered(AssociationKey associationKey);
|
public void associationKeyRegistered(AssociationKey associationKey);
|
||||||
public void foundCircularAssociationKey(AssociationKey associationKey, AttributeDefinition attributeDefinition);
|
public FetchSource registeredFetchSource(AssociationKey associationKey);
|
||||||
|
public void foundCircularAssociation(AssociationAttributeDefinition attributeDefinition);
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ import org.hibernate.type.Type;
|
||||||
* calls out to the strategy the strategy then decides the semantics (literally, the meaning).
|
* calls out to the strategy the strategy then decides the semantics (literally, the meaning).
|
||||||
* <p/>
|
* <p/>
|
||||||
* The visitor will, however, stop if it sees a "duplicate" AssociationKey. In such a case, the walker would call
|
* The visitor will, however, stop if it sees a "duplicate" AssociationKey. In such a case, the walker would call
|
||||||
* {@link AssociationVisitationStrategy#foundCircularAssociationKey} and stop walking any further down that graph any
|
* {@link AssociationVisitationStrategy#foundCircularAssociation} and stop walking any further down that graph any
|
||||||
* further.
|
* further.
|
||||||
*
|
*
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
|
@ -152,17 +152,21 @@ public class MetamodelGraphWalker {
|
||||||
final PropertyPath subPath = currentPropertyPath.append( attributeDefinition.getName() );
|
final PropertyPath subPath = currentPropertyPath.append( attributeDefinition.getName() );
|
||||||
log.debug( "Visiting attribute path : " + subPath.getFullPath() );
|
log.debug( "Visiting attribute path : " + subPath.getFullPath() );
|
||||||
|
|
||||||
|
|
||||||
if ( attributeDefinition.getType().isAssociationType() ) {
|
if ( attributeDefinition.getType().isAssociationType() ) {
|
||||||
final AssociationKey associationKey = ( (AssociationAttributeDefinition) attributeDefinition ).getAssociationKey();
|
final AssociationAttributeDefinition associationAttributeDefinition =
|
||||||
|
(AssociationAttributeDefinition) attributeDefinition;
|
||||||
|
final AssociationKey associationKey = associationAttributeDefinition.getAssociationKey();
|
||||||
if ( isDuplicateAssociationKey( associationKey ) ) {
|
if ( isDuplicateAssociationKey( associationKey ) ) {
|
||||||
log.debug( "Property path deemed to be circular : " + subPath.getFullPath() );
|
log.debug( "Property path deemed to be circular : " + subPath.getFullPath() );
|
||||||
strategy.foundCircularAssociationKey( associationKey, attributeDefinition );
|
strategy.foundCircularAssociation( associationAttributeDefinition );
|
||||||
// EARLY EXIT!!!
|
// EARLY EXIT!!!
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean continueWalk = strategy.startingAttribute( attributeDefinition );
|
|
||||||
|
boolean continueWalk = strategy.startingAttribute( attributeDefinition );
|
||||||
if ( continueWalk ) {
|
if ( continueWalk ) {
|
||||||
final PropertyPath old = currentPropertyPath;
|
final PropertyPath old = currentPropertyPath;
|
||||||
currentPropertyPath = subPath;
|
currentPropertyPath = subPath;
|
||||||
|
|
|
@ -26,6 +26,7 @@ package org.hibernate.test.loadplans.plans;
|
||||||
import org.hibernate.cfg.Configuration;
|
import org.hibernate.cfg.Configuration;
|
||||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
|
||||||
|
import org.hibernate.loader.plan2.spi.BidirectionalEntityFetch;
|
||||||
import org.hibernate.test.annotations.Country;
|
import org.hibernate.test.annotations.Country;
|
||||||
import org.hibernate.test.annotations.collectionelement.Boy;
|
import org.hibernate.test.annotations.collectionelement.Boy;
|
||||||
import org.hibernate.test.annotations.collectionelement.Matrix;
|
import org.hibernate.test.annotations.collectionelement.Matrix;
|
||||||
|
@ -225,18 +226,18 @@ public class LoadPlanStructureAssertionTest extends BaseUnitTestCase {
|
||||||
FetchSource.class,
|
FetchSource.class,
|
||||||
cardFieldElementGraph.getIdentifierDescription()
|
cardFieldElementGraph.getIdentifierDescription()
|
||||||
);
|
);
|
||||||
assertEquals( 1, cardFieldElementGraphIdAsFetchSource.getFetches().length );
|
assertEquals( 2, cardFieldElementGraphIdAsFetchSource.getFetches().length );
|
||||||
|
|
||||||
// BidirectionalEntityFetch circularCardFetch = assertTyping(
|
BidirectionalEntityFetch circularCardFetch = assertTyping(
|
||||||
// BidirectionalEntityFetch.class,
|
BidirectionalEntityFetch.class,
|
||||||
// fieldsElementCompositeIdFetch.getFetches()[0]
|
cardFieldElementGraphIdAsFetchSource.getFetches()[0]
|
||||||
// );
|
);
|
||||||
// assertSame( circularCardFetch.getTargetEntityReference(), cardReturn );
|
assertSame( circularCardFetch.getTargetEntityReference(), cardReturn );
|
||||||
|
|
||||||
// the fetch above is to the other key-many-to-one for CardField.primaryKey composite: key
|
// the fetch above is to the other key-many-to-one for CardField.primaryKey composite: key
|
||||||
EntityFetch keyFetch = assertTyping(
|
EntityFetch keyFetch = assertTyping(
|
||||||
EntityFetch.class,
|
EntityFetch.class,
|
||||||
cardFieldElementGraphIdAsFetchSource.getFetches()[0]
|
cardFieldElementGraphIdAsFetchSource.getFetches()[1]
|
||||||
);
|
);
|
||||||
assertEquals( Key.class.getName(), keyFetch.getEntityPersister().getEntityName() );
|
assertEquals( Key.class.getName(), keyFetch.getEntityPersister().getEntityName() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
package org.hibernate.test.loadplans.walking;
|
package org.hibernate.test.loadplans.walking;
|
||||||
|
|
||||||
import org.hibernate.annotations.common.util.StringHelper;
|
import org.hibernate.annotations.common.util.StringHelper;
|
||||||
|
import org.hibernate.loader.plan2.spi.FetchSource;
|
||||||
import org.hibernate.persister.walking.spi.AnyMappingDefinition;
|
import org.hibernate.persister.walking.spi.AnyMappingDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
import org.hibernate.persister.walking.spi.AssociationAttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.AssociationKey;
|
import org.hibernate.persister.walking.spi.AssociationKey;
|
||||||
|
@ -32,7 +33,6 @@ import org.hibernate.persister.walking.spi.AttributeDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
import org.hibernate.persister.walking.spi.CollectionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
import org.hibernate.persister.walking.spi.CollectionElementDefinition;
|
||||||
import org.hibernate.persister.walking.spi.CollectionIndexDefinition;
|
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.CompositionDefinition;
|
||||||
import org.hibernate.persister.walking.spi.EntityDefinition;
|
import org.hibernate.persister.walking.spi.EntityDefinition;
|
||||||
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
import org.hibernate.persister.walking.spi.EntityIdentifierDefinition;
|
||||||
|
@ -246,15 +246,19 @@ public class LoggingAssociationVisitationStrategy implements AssociationVisitati
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void foundCircularAssociationKey(
|
public FetchSource registeredFetchSource(AssociationKey associationKey) {
|
||||||
AssociationKey associationKey,
|
return null;
|
||||||
AttributeDefinition attributeDefinition) {
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void foundCircularAssociation(
|
||||||
|
AssociationAttributeDefinition attributeDefinition) {
|
||||||
System.out.println(
|
System.out.println(
|
||||||
String.format(
|
String.format(
|
||||||
"%s Handling circular association attribute (%s) : %s",
|
"%s Handling circular association attribute (%s) : %s",
|
||||||
StringHelper.repeat( ">>", depth + 1 ),
|
StringHelper.repeat( ">>", depth + 1 ),
|
||||||
attributeDefinition.toString(),
|
attributeDefinition.toString(),
|
||||||
associationKey.toString()
|
attributeDefinition.getAssociationKey().toString()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue