use of org.hibernate.loader.plan.spi.CollectionReturn in project hibernate-orm by hibernate.
the class AbstractLoadPlanBuildingAssociationVisitationStrategy method startingCollection.
@Override
public void startingCollection(CollectionDefinition collectionDefinition) {
// see if the EntityDefinition is a root...
final boolean isRoot = fetchSourceStack.isEmpty();
if (!isRoot) {
// if not, this call should represent a fetch which should have been handled in #startingAttribute
return;
}
log.tracef("%s Starting root collection : %s", StringHelper.repeat(">>", fetchSourceStack.size()), collectionDefinition.getCollectionPersister().getRole());
// if we get here, it is a root
if (!supportsRootCollectionReturns()) {
throw new HibernateException("This strategy does not support root collection returns");
}
final CollectionReturn collectionReturn = new CollectionReturnImpl(collectionDefinition, querySpaces);
pushToCollectionStack(collectionReturn);
addRootReturn(collectionReturn);
associationKeyRegistered(new AssociationKey(((Joinable) collectionDefinition.getCollectionPersister()).getTableName(), ((Joinable) collectionDefinition.getCollectionPersister()).getKeyColumnNames()));
}
use of org.hibernate.loader.plan.spi.CollectionReturn in project hibernate-orm by hibernate.
the class AbstractLoadQueryDetails method generate.
/**
* Main entry point for properly handling the FROM clause and and joins and restrictions
*
*/
protected void generate() {
// There are 2 high-level requirements to perform here:
// 1) Determine the SQL required to carry out the given LoadPlan (and fulfill
// {@code LoadQueryDetails#getSqlStatement()}). SelectStatementBuilder collects the ongoing efforts to
// build the needed SQL.
// 2) Determine how to read information out of the ResultSet resulting from executing the indicated SQL
// (the SQL aliases). ReaderCollector and friends are where this work happens, ultimately
// producing a ResultSetProcessor
final SelectStatementBuilder select = new SelectStatementBuilder(queryProcessor.getSessionFactory().getDialect());
// LoadPlan is broken down into 2 high-level pieces that we need to process here.
//
// First is the QuerySpaces, which roughly equates to the SQL FROM-clause. We'll cycle through
// those first, generating aliases into the AliasContext in addition to writing SQL FROM-clause information
// into SelectStatementBuilder. The AliasContext is populated here and the reused while process the SQL
// SELECT-clause into the SelectStatementBuilder and then again also to build the ResultSetProcessor
applyRootReturnTableFragments(select);
if (shouldApplyRootReturnFilterBeforeKeyRestriction()) {
applyRootReturnFilterRestrictions(select);
// add restrictions...
// first, the load key restrictions (which entity(s)/collection(s) do we want to load?)
applyKeyRestriction(select, getRootTableAlias(), keyColumnNames, getQueryBuildingParameters().getBatchSize());
} else {
// add restrictions...
// first, the load key restrictions (which entity(s)/collection(s) do we want to load?)
applyKeyRestriction(select, getRootTableAlias(), keyColumnNames, getQueryBuildingParameters().getBatchSize());
applyRootReturnFilterRestrictions(select);
}
applyRootReturnWhereJoinRestrictions(select);
applyRootReturnOrderByFragments(select);
// then move on to joins...
applyRootReturnSelectFragments(select);
queryProcessor.processQuerySpaceJoins(getRootQuerySpace(), select);
// Next, we process the Returns and Fetches building the SELECT clause and at the same time building
// Readers for reading the described results out of a SQL ResultSet
FetchStats fetchStats = null;
if (FetchSource.class.isInstance(rootReturn)) {
fetchStats = queryProcessor.processFetches((FetchSource) rootReturn, select, getReaderCollector());
} else if (CollectionReturn.class.isInstance(rootReturn)) {
final CollectionReturn collectionReturn = (CollectionReturn) rootReturn;
if (collectionReturn.getElementGraph() != null) {
fetchStats = queryProcessor.processFetches(collectionReturn.getElementGraph(), select, getReaderCollector());
}
// TODO: what about index???
}
if (fetchStats != null && fetchStats.getJoinedBagAttributeFetches().size() > 1) {
final List<String> bagRoles = new ArrayList<>();
for (CollectionAttributeFetch bagFetch : fetchStats.getJoinedBagAttributeFetches()) {
bagRoles.add(bagFetch.getCollectionPersister().getRole());
}
throw new MultipleBagFetchException(bagRoles);
}
LoadPlanTreePrinter.INSTANCE.logTree(loadPlan, queryProcessor.getAliasResolutionContext());
this.sqlStatement = select.toStatementString();
this.resultSetProcessor = new ResultSetProcessorImpl(loadPlan, queryProcessor.getAliasResolutionContext(), getReaderCollector().buildRowReader(), shouldUseOptionalEntityInstance(), isSubselectLoadingEnabled(fetchStats));
}
use of org.hibernate.loader.plan.spi.CollectionReturn in project hibernate-orm by hibernate.
the class BatchingLoadQueryDetailsFactory method makeCollectionLoadQueryDetails.
/**
* Constructs a BasicCollectionLoadQueryDetails object from the given inputs.
*
* @param collectionPersister The collection persister.
* @param loadPlan The load plan.
* @param buildingParameters And influencers that would affect the generated SQL (mostly we are concerned with those
* that add additional joins here)
*
* @return The EntityLoadQueryDetails
*/
public LoadQueryDetails makeCollectionLoadQueryDetails(CollectionPersister collectionPersister, LoadPlan loadPlan, QueryBuildingParameters buildingParameters) {
final CollectionReturn rootReturn = RootHelper.INSTANCE.extractRootReturn(loadPlan, CollectionReturn.class);
final AliasResolutionContextImpl aliasResolutionContext = new AliasResolutionContextImpl(collectionPersister.getFactory());
return collectionPersister.isOneToMany() ? new OneToManyLoadQueryDetails(loadPlan, aliasResolutionContext, rootReturn, buildingParameters, collectionPersister.getFactory()) : new BasicCollectionLoadQueryDetails(loadPlan, aliasResolutionContext, rootReturn, buildingParameters, collectionPersister.getFactory());
}
use of org.hibernate.loader.plan.spi.CollectionReturn in project hibernate-orm by hibernate.
the class LoadPlanBuilderTest method testCollectionInitializerCase.
@Test
public void testCollectionInitializerCase() {
CollectionPersister cp = sessionFactory().getCollectionPersister(Poster.class.getName() + ".messages");
FetchStyleLoadPlanBuildingAssociationVisitationStrategy strategy = new FetchStyleLoadPlanBuildingAssociationVisitationStrategy(sessionFactory(), LoadQueryInfluencers.NONE, LockMode.NONE);
LoadPlan plan = MetamodelDrivenLoadPlanBuilder.buildRootCollectionLoadPlan(strategy, cp);
assertFalse(plan.hasAnyScalarReturns());
assertEquals(1, plan.getReturns().size());
Return rtn = plan.getReturns().get(0);
CollectionReturn collectionReturn = ExtraAssertions.assertTyping(CollectionReturn.class, rtn);
assertNotNull(collectionReturn.getElementGraph());
assertNotNull(collectionReturn.getElementGraph().getFetches());
// the collection Message elements are fetched, but Message.poster is not fetched
// (because that collection is owned by that Poster)
assertEquals(0, collectionReturn.getElementGraph().getFetches().length);
EntityReference entityReference = ExtraAssertions.assertTyping(EntityReference.class, collectionReturn.getElementGraph());
assertNotNull(entityReference.getFetches());
assertEquals(0, entityReference.getFetches().length);
LoadPlanTreePrinter.INSTANCE.logTree(plan, new AliasResolutionContextImpl(sessionFactory()));
}
Aggregations