下面列出了org.hibernate.dialect.lock.LockingStrategyException#org.hibernate.loader.MultipleBagFetchException 实例代码,或者点击链接到github查看源代码,也可以在右侧发表评论。
@Test
void multipleBagFetchException() {
log.info("MultipleBagFetchException on @EntityGraph with multiple attribute nodes");
assertThatThrownBy(() -> bookRepository.findByPublicationDateBetween(
LocalDate.parse("2000-01-01"), LocalDate.parse("2020-01-01"),
Sort.by(ASC, "publicationDate")))
.hasRootCauseInstanceOf(MultipleBagFetchException.class)
.hasMessageContaining("cannot simultaneously fetch multiple bags");
//Trying to fetch multiple many-to-many relations
//List<Author> authors and List<Category> categories
//that both have type List results in exception
//org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
}
/**
* 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 )
);
}