use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class CriteriaEntityGraphTest method testFetchSemanticsWithDeepSubgraph.
@Test
void testFetchSemanticsWithDeepSubgraph() {
scope.inTransaction(session -> {
final RootGraphImplementor<Cat> eg = session.createEntityGraph(Cat.class);
eg.addSubgraph("owner", Person.class).addSubgraph("company", ExpressCompany.class);
final SelectStatement sqlAst = buildSqlSelectAst(Cat.class, eg, GraphSemantic.FETCH, session);
// Check the from-clause
assertEntityValuedJoinedGroup(sqlAst, "owner", Person.class, tableGroup -> {
List<TableGroupJoin> tableGroupJoins = tableGroup.getTableGroupJoins();
Map<String, Class<? extends TableGroup>> tableGroupByName = tableGroupJoins.stream().map(TableGroupJoin::getJoinedGroup).collect(Collectors.toMap(tg -> tg.getModelPart().getPartName(), TableGroup::getClass));
Map<String, Class<? extends TableGroup>> expectedTableGroupByName = new HashMap<>();
expectedTableGroupByName.put("homeAddress", StandardVirtualTableGroup.class);
expectedTableGroupByName.put("company", LazyTableGroup.class);
assertThat(tableGroupByName, is(expectedTableGroupByName));
});
// Check the domain-result graph
assertDomainResult(sqlAst, Cat.class, "owner", Person.class, entityFetch -> {
assertThat(entityFetch, instanceOf(EntityFetchJoinedImpl.class));
final EntityResult ownerEntityResult = ((EntityFetchJoinedImpl) entityFetch).getEntityResult();
final Map<String, Class<? extends Fetch>> fetchClassByAttributeName = ownerEntityResult.getFetches().stream().collect(Collectors.toMap(fetch -> fetch.getFetchedMapping().getPartName(), Fetch::getClass));
final Map<String, Class<? extends Fetch>> expectedFetchClassByAttributeName = new HashMap<>();
expectedFetchClassByAttributeName.put("homeAddress", EmbeddableFetchImpl.class);
expectedFetchClassByAttributeName.put("pets", DelayedCollectionFetch.class);
expectedFetchClassByAttributeName.put("company", EntityFetchJoinedImpl.class);
assertThat(fetchClassByAttributeName, is(expectedFetchClassByAttributeName));
Fetchable fetchable = getFetchable("company", Person.class);
final Fetch companyFetch = ownerEntityResult.findFetch(fetchable);
List<Fetch> fetches = ownerEntityResult.getFetches();
assertThat(companyFetch, notNullValue());
final EntityResult companyEntityResult = ((EntityFetchJoinedImpl) companyFetch).getEntityResult();
assertThat(companyEntityResult.getFetches(), hasSize(1));
final Fetch shipAddressesFetch = companyEntityResult.getFetches().get(0);
assertThat(shipAddressesFetch.getFetchedMapping().getPartName(), is("shipAddresses"));
assertThat(shipAddressesFetch, instanceOf(DelayedCollectionFetch.class));
});
});
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class EntityGraphLoadPlanBuilderTest method testFetchLoadPlanBuildingWithDeepSubgraph.
@Test
void testFetchLoadPlanBuildingWithDeepSubgraph() {
scope.inTransaction(em -> {
final RootGraphImplementor<Cat> eg = em.createEntityGraph(Cat.class);
eg.addSubgraph("owner", Person.class).addSubgraph("company", ExpressCompany.class);
final SelectStatement sqlAst = buildSqlSelectAst(Cat.class, eg, GraphSemantic.FETCH, scope);
// Check the from-clause
assertEntityValuedJoinedGroup(sqlAst, "owner", Person.class, tableGroup -> {
List<TableGroupJoin> tableGroupJoins = tableGroup.getTableGroupJoins();
Map<String, Class<? extends TableGroup>> tableGroupByName = tableGroupJoins.stream().map(TableGroupJoin::getJoinedGroup).collect(Collectors.toMap(tg -> tg.getModelPart().getPartName(), TableGroup::getClass));
Map<String, Class<? extends TableGroup>> expectedTableGroupByName = new HashMap<>();
expectedTableGroupByName.put("homeAddress", StandardVirtualTableGroup.class);
expectedTableGroupByName.put("company", LazyTableGroup.class);
assertThat(tableGroupByName, is(expectedTableGroupByName));
});
// Check the domain-result graph
assertDomainResult(sqlAst, Cat.class, "owner", Person.class, entityFetch -> {
assertThat(entityFetch, instanceOf(EntityFetchJoinedImpl.class));
final EntityResult ownerEntityResult = ((EntityFetchJoinedImpl) entityFetch).getEntityResult();
final Map<String, Class<? extends Fetch>> fetchClassByAttributeName = ownerEntityResult.getFetches().stream().collect(Collectors.toMap(fetch -> fetch.getFetchedMapping().getPartName(), Fetch::getClass));
final Map<String, Class<? extends Fetch>> expectedFetchClassByAttributeName = new HashMap<>();
expectedFetchClassByAttributeName.put("homeAddress", EmbeddableFetchImpl.class);
expectedFetchClassByAttributeName.put("pets", DelayedCollectionFetch.class);
expectedFetchClassByAttributeName.put("company", EntityFetchJoinedImpl.class);
assertThat(fetchClassByAttributeName, is(expectedFetchClassByAttributeName));
Fetchable fetchable = getFetchable("company", Person.class);
final Fetch companyFetch = ownerEntityResult.findFetch(fetchable);
assertThat(companyFetch, notNullValue());
final EntityResult companyEntityResult = ((EntityFetchJoinedImpl) companyFetch).getEntityResult();
assertThat(companyEntityResult.getFetches(), hasSize(1));
final Fetch shipAddressesFetch = companyEntityResult.getFetches().get(0);
assertThat(shipAddressesFetch.getFetchedMapping().getPartName(), is("shipAddresses"));
assertThat(shipAddressesFetch, instanceOf(DelayedCollectionFetch.class));
});
});
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class HqlEntityGraphTest method testFetchSemanticsWithDeepSubgraph.
@Test
void testFetchSemanticsWithDeepSubgraph() {
scope.inTransaction(session -> {
final RootGraphImplementor<Cat> eg = session.createEntityGraph(Cat.class);
eg.addSubgraph("owner", Person.class).addSubgraph("company", ExpressCompany.class);
final SelectStatement sqlAst = buildSqlSelectAst(Cat.class, "select c from Cat as c", eg, GraphSemantic.FETCH, session);
// Check the from-clause
assertEntityValuedJoinedGroup(sqlAst, "owner", Person.class, tableGroup -> {
List<TableGroupJoin> tableGroupJoins = tableGroup.getTableGroupJoins();
Map<String, Class<? extends TableGroup>> tableGroupByName = tableGroupJoins.stream().map(TableGroupJoin::getJoinedGroup).collect(Collectors.toMap(tg -> tg.getModelPart().getPartName(), TableGroup::getClass));
Map<String, Class<? extends TableGroup>> expectedTableGroupByName = new HashMap<>();
expectedTableGroupByName.put("homeAddress", StandardVirtualTableGroup.class);
expectedTableGroupByName.put("company", LazyTableGroup.class);
assertThat(tableGroupByName, is(expectedTableGroupByName));
});
// Check the domain-result graph
assertDomainResult(sqlAst, Cat.class, "owner", Person.class, entityFetch -> {
assertThat(entityFetch, instanceOf(EntityFetchJoinedImpl.class));
final EntityResult ownerEntityResult = ((EntityFetchJoinedImpl) entityFetch).getEntityResult();
final Map<String, Class<? extends Fetch>> fetchClassByAttributeName = ownerEntityResult.getFetches().stream().collect(Collectors.toMap(fetch -> fetch.getFetchedMapping().getPartName(), Fetch::getClass));
final Map<String, Class<? extends Fetch>> expectedFetchClassByAttributeName = new HashMap<>();
expectedFetchClassByAttributeName.put("homeAddress", EmbeddableFetchImpl.class);
expectedFetchClassByAttributeName.put("pets", DelayedCollectionFetch.class);
expectedFetchClassByAttributeName.put("company", EntityFetchJoinedImpl.class);
assertThat(fetchClassByAttributeName, is(expectedFetchClassByAttributeName));
Fetchable fetchable = getFetchable("company", Person.class);
final Fetch companyFetch = ownerEntityResult.findFetch(fetchable);
assertThat(companyFetch, notNullValue());
final EntityResult companyEntityResult = ((EntityFetchJoinedImpl) companyFetch).getEntityResult();
assertThat(companyEntityResult.getFetches(), hasSize(1));
final Fetch shipAddressesFetch = companyEntityResult.getFetches().get(0);
assertThat(shipAddressesFetch.getFetchedMapping().getPartName(), is("shipAddresses"));
assertThat(shipAddressesFetch, instanceOf(DelayedCollectionFetch.class));
});
});
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class ToOneAttributeMapping method generateFetch.
@Override
public EntityFetch generateFetch(FetchParent fetchParent, NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, String resultVariable, DomainResultCreationState creationState) {
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final FromClauseAccess fromClauseAccess = sqlAstCreationState.getFromClauseAccess();
final TableGroup parentTableGroup = fromClauseAccess.getTableGroup(fetchParent.getNavigablePath());
final NavigablePath parentNavigablePath = fetchablePath.getParent();
assert parentNavigablePath.equals(fetchParent.getNavigablePath()) || fetchParent.getNavigablePath() instanceof TreatedNavigablePath && parentNavigablePath.equals(fetchParent.getNavigablePath().getRealParent());
if (fetchTiming == FetchTiming.IMMEDIATE && selected) {
final TableGroup tableGroup;
if (fetchParent instanceof EntityResultJoinedSubclassImpl && ((EntityPersister) fetchParent.getReferencedModePart()).findDeclaredAttributeMapping(getPartName()) == null) {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(fetchablePath, parentTableGroup, resultVariable, getJoinType(fetchablePath, parentTableGroup), true, false, creationState.getSqlAstCreationState());
parentTableGroup.addTableGroupJoin(tableGroupJoin);
tableGroup = tableGroupJoin.getJoinedGroup();
fromClauseAccess.registerTableGroup(fetchablePath, tableGroup);
} else {
tableGroup = fromClauseAccess.resolveTableGroup(fetchablePath, np -> {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(fetchablePath, parentTableGroup, resultVariable, getDefaultSqlAstJoinType(parentTableGroup), true, false, creationState.getSqlAstCreationState());
parentTableGroup.addTableGroupJoin(tableGroupJoin);
return tableGroupJoin.getJoinedGroup();
});
}
final boolean added = creationState.registerVisitedAssociationKey(foreignKeyDescriptor.getAssociationKey());
AssociationKey additionalAssociationKey = null;
if (cardinality == Cardinality.LOGICAL_ONE_TO_ONE && bidirectionalAttributeName != null) {
final ModelPart bidirectionalModelPart = entityMappingType.findSubPart(bidirectionalAttributeName);
// Add the inverse association key side as well to be able to resolve to a CircularFetch
if (bidirectionalModelPart instanceof ToOneAttributeMapping) {
assert bidirectionalModelPart.getPartMappingType() == declaringTableGroupProducer;
final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey();
if (creationState.registerVisitedAssociationKey(secondKey)) {
additionalAssociationKey = secondKey;
}
}
}
final EntityFetchJoinedImpl entityFetchJoined = new EntityFetchJoinedImpl(fetchParent, this, tableGroup, fetchablePath, creationState);
if (added) {
creationState.removeVisitedAssociationKey(foreignKeyDescriptor.getAssociationKey());
}
if (additionalAssociationKey != null) {
creationState.removeVisitedAssociationKey(additionalAssociationKey);
}
return entityFetchJoined;
}
/*
1. No JoinTable
Model:
EntityA{
@ManyToOne
EntityB b
}
EntityB{
@ManyToOne
EntityA a
}
Relational:
ENTITY_A( id )
ENTITY_B( id, entity_a_id)
1.1 EntityA -> EntityB : as keyResult we need ENTITY_B.id
1.2 EntityB -> EntityA : as keyResult we need ENTITY_B.entity_a_id (FK referring column)
2. JoinTable
*/
final ForeignKeyDescriptor.Nature resolvingKeySideOfForeignKey = creationState.getCurrentlyResolvingForeignKeyPart();
final ForeignKeyDescriptor.Nature side;
if (resolvingKeySideOfForeignKey == ForeignKeyDescriptor.Nature.KEY && this.sideNature == ForeignKeyDescriptor.Nature.TARGET) {
// If we are currently resolving the key part of a foreign key we do not want to add joins.
// So if the lhs of this association is the target of the FK, we have to use the KEY part to avoid a join
side = ForeignKeyDescriptor.Nature.KEY;
} else {
side = this.sideNature;
}
final DomainResult<?> keyResult = foreignKeyDescriptor.createDomainResult(fetchablePath, parentTableGroup, side, creationState);
final boolean selectByUniqueKey = isSelectByUniqueKey(side);
if (fetchTiming == FetchTiming.IMMEDIATE) {
return new EntityFetchSelectImpl(fetchParent, this, fetchablePath, keyResult, selectByUniqueKey, creationState);
}
return new EntityDelayedFetchImpl(fetchParent, this, fetchablePath, keyResult, selectByUniqueKey);
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class ToOneAttributeMapping method createTableGroupJoin.
@Override
public TableGroupJoin createTableGroupJoin(NavigablePath navigablePath, TableGroup lhs, String explicitSourceAlias, SqlAstJoinType requestedJoinType, boolean fetched, boolean addsPredicate, SqlAliasBaseGenerator aliasBaseGenerator, SqlExpressionResolver sqlExpressionResolver, FromClauseAccess fromClauseAccess, SqlAstCreationContext creationContext) {
// This is vital for the map key property check that comes next
assert !(lhs instanceof PluralTableGroup);
TableGroup parentTableGroup = lhs;
ModelPartContainer parentContainer = lhs.getModelPart();
StringBuilder embeddablePathSb = null;
// Traverse up embeddable table groups until we find a table group for a collection part
while (!(parentContainer instanceof CollectionPart)) {
if (parentContainer instanceof EmbeddableValuedModelPart) {
if (embeddablePathSb == null) {
embeddablePathSb = new StringBuilder();
}
embeddablePathSb.insert(0, parentContainer.getPartName() + ".");
parentTableGroup = fromClauseAccess.findTableGroup(parentTableGroup.getNavigablePath().getParent());
parentContainer = parentTableGroup.getModelPart();
} else {
break;
}
}
final SqlAstJoinType joinType;
if (requestedJoinType == null) {
joinType = SqlAstJoinType.INNER;
} else {
joinType = requestedJoinType;
}
// we check if this attribute is the map key property to reuse the existing index table group
if (CollectionPart.Nature.ELEMENT.getName().equals(parentTableGroup.getNavigablePath().getUnaliasedLocalName()) && !addsPredicate && (joinType == SqlAstJoinType.INNER || joinType == SqlAstJoinType.LEFT)) {
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(parentTableGroup.getNavigablePath().getParent());
final String indexPropertyName = pluralTableGroup.getModelPart().getIndexMetadata().getIndexPropertyName();
final String pathName;
if (embeddablePathSb != null) {
pathName = embeddablePathSb.append(getAttributeName()).toString();
} else {
pathName = getAttributeName();
}
if (pathName.equals(indexPropertyName)) {
final TableGroup indexTableGroup = pluralTableGroup.getIndexTableGroup();
// If this is the map key property, we can reuse the index table group
initializeIfNeeded(lhs, requestedJoinType, indexTableGroup);
return new TableGroupJoin(navigablePath, joinType, new MappedByTableGroup(navigablePath, this, indexTableGroup, fetched, pluralTableGroup, (np, tableExpression) -> {
if (!canUseParentTableGroup) {
return false;
}
NavigablePath path = np.getParent();
// Fast path
if (path != null && navigablePath.equals(path)) {
return targetKeyPropertyNames.contains(np.getUnaliasedLocalName()) && identifyingColumnsTableExpression.equals(tableExpression);
}
final StringBuilder sb = new StringBuilder(np.getFullPath().length());
sb.append(np.getUnaliasedLocalName());
while (path != null && !navigablePath.equals(path)) {
sb.insert(0, '.');
sb.insert(0, path.getUnaliasedLocalName());
path = path.getParent();
}
return path != null && navigablePath.equals(path) && targetKeyPropertyNames.contains(sb.toString()) && identifyingColumnsTableExpression.equals(tableExpression);
}), null);
}
}
final LazyTableGroup lazyTableGroup = createRootTableGroupJoin(navigablePath, lhs, explicitSourceAlias, requestedJoinType, fetched, null, aliasBaseGenerator, sqlExpressionResolver, fromClauseAccess, creationContext);
final TableGroupJoin join = new TableGroupJoin(navigablePath, joinType, lazyTableGroup, null);
final TableReference lhsTableReference = lhs.resolveTableReference(navigablePath, identifyingColumnsTableExpression);
lazyTableGroup.setTableGroupInitializerCallback(tableGroup -> join.applyPredicate(foreignKeyDescriptor.generateJoinPredicate(sideNature == ForeignKeyDescriptor.Nature.TARGET ? lhsTableReference : tableGroup.getPrimaryTableReference(), sideNature == ForeignKeyDescriptor.Nature.TARGET ? tableGroup.getPrimaryTableReference() : lhsTableReference, sqlExpressionResolver, creationContext)));
return join;
}
Aggregations