use of org.hibernate.metamodel.mapping.ModelPart in project hibernate-orm by hibernate.
the class ToOneAttributeMapping method resolveCircularFetch.
@Override
public Fetch resolveCircularFetch(NavigablePath fetchablePath, FetchParent fetchParent, FetchTiming fetchTiming, DomainResultCreationState creationState) {
final AssociationKey associationKey = foreignKeyDescriptor.getAssociationKey();
if (creationState.isAssociationKeyVisited(associationKey) || bidirectionalAttributeName != null && !creationState.isRegisteringVisitedAssociationKeys()) {
NavigablePath parentNavigablePath = fetchablePath.getParent();
assert parentNavigablePath.equals(fetchParent.getNavigablePath());
/*
@Entity
public class Card {
@Id
private String id;
@ManyToOne
private CardField field;
}
@Entity
public class CardField {
@EmbeddedId
private PrimaryKey primaryKey;
}
@Embeddable
public class PrimaryKey {
@ManyToOne(optional = false)
private Card card;
@ManyToOne(optional = false)
private Key key;
}
*/
if (parentNavigablePath.getLocalName().equals(ForeignKeyDescriptor.PART_NAME)) {
// todo (6.0): maybe it's better to have a flag in creation state that marks if we are building a circular fetch domain result already to skip this?
return null;
}
ModelPart parentModelPart = creationState.resolveModelPart(parentNavigablePath);
if (parentModelPart instanceof EmbeddedIdentifierMappingImpl) {
while (parentNavigablePath instanceof EntityIdentifierNavigablePath) {
parentNavigablePath = parentNavigablePath.getParent();
assert parentNavigablePath != null;
parentModelPart = creationState.resolveModelPart(parentNavigablePath);
}
}
while (parentModelPart instanceof EmbeddableValuedFetchable) {
parentNavigablePath = parentNavigablePath.getParent();
assert parentNavigablePath != null;
parentModelPart = creationState.resolveModelPart(parentNavigablePath);
}
if (isBidirectionalAttributeName(parentNavigablePath, parentModelPart, fetchablePath, creationState)) {
return createCircularBiDirectionalFetch(fetchablePath, fetchParent, parentNavigablePath, creationState);
}
/*
class Child {
@OneToOne
private Mother mother;
}
class Mother {
@OneToOne
private Child stepMother;
}
We have a circularity but it is not bidirectional
*/
final TableGroup parentTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().getTableGroup(fetchParent.getNavigablePath());
final DomainResult<?> foreignKeyDomainResult;
assert !creationState.isResolvingCircularFetch();
try {
creationState.setResolvingCircularFetch(true);
foreignKeyDomainResult = foreignKeyDescriptor.createDomainResult(fetchablePath, parentTableGroup, sideNature, creationState);
} finally {
creationState.setResolvingCircularFetch(false);
}
return new CircularFetchImpl(this, getEntityMappingType(), fetchTiming, fetchablePath, fetchParent, this, isSelectByUniqueKey(sideNature), fetchablePath, foreignKeyDomainResult);
}
return null;
}
use of org.hibernate.metamodel.mapping.ModelPart 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.metamodel.mapping.ModelPart in project hibernate-orm by hibernate.
the class MappingModelCreationHelper method interpretPluralAttributeMappingKeyDescriptor.
private static void interpretPluralAttributeMappingKeyDescriptor(PluralAttributeMappingImpl attributeMapping, Collection bootValueMapping, CollectionPersister collectionDescriptor, ManagedMappingType declaringType, Dialect dialect, MappingModelCreationProcess creationProcess) {
ModelPart attributeMappingSubPart = null;
if (!StringHelper.isEmpty(collectionDescriptor.getMappedByProperty())) {
attributeMappingSubPart = ((ModelPartContainer) attributeMapping.getElementDescriptor().getPartMappingType()).findSubPart(collectionDescriptor.getMappedByProperty(), null);
}
if (attributeMappingSubPart instanceof ToOneAttributeMapping) {
final ToOneAttributeMapping referencedAttributeMapping = (ToOneAttributeMapping) attributeMappingSubPart;
setReferencedAttributeForeignKeyDescriptor(attributeMapping, referencedAttributeMapping, referencedAttributeMapping.findContainingEntityMapping().getEntityPersister(), collectionDescriptor.getMappedByProperty(), dialect, creationProcess);
return;
}
final KeyValue bootValueMappingKey = bootValueMapping.getKey();
final Type keyType = bootValueMappingKey.getType();
final ModelPart fkTarget;
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
final boolean isReferenceToPrimaryKey = lhsPropertyName == null;
final ManagedMappingType keyDeclaringType;
if (collectionDescriptor.getElementType().isEntityType()) {
keyDeclaringType = ((QueryableCollection) collectionDescriptor).getElementPersister();
} else {
// This is not "really correct" but it is as good as it gets.
// The key declaring type serves as declaring type for the inverse model part of a FK.
// Most of the time, there is a proper managed type, but not for basic collections.
// Since the declaring type is needed for certain operations, we use the one from the target side of the FK
keyDeclaringType = declaringType;
}
if (isReferenceToPrimaryKey) {
fkTarget = collectionDescriptor.getOwnerEntityPersister().getIdentifierMapping();
} else {
fkTarget = declaringType.findAttributeMapping(lhsPropertyName);
}
if (keyType instanceof BasicType) {
assert bootValueMappingKey.getColumnSpan() == 1;
assert fkTarget instanceof BasicValuedModelPart;
final BasicValuedModelPart simpleFkTarget = (BasicValuedModelPart) fkTarget;
final String tableExpression = getTableIdentifierExpression(bootValueMappingKey.getTable(), creationProcess);
final SelectableMapping keySelectableMapping = SelectableMappingImpl.from(tableExpression, bootValueMappingKey.getSelectables().get(0), (JdbcMapping) keyType, dialect, creationProcess.getSqmFunctionRegistry());
attributeMapping.setForeignKeyDescriptor(new SimpleForeignKeyDescriptor(keyDeclaringType, simpleFkTarget, null, keySelectableMapping, simpleFkTarget, isReferenceToPrimaryKey, ((SimpleValue) bootValueMappingKey).isConstrained()));
} else if (fkTarget instanceof EmbeddableValuedModelPart) {
final EmbeddedForeignKeyDescriptor embeddedForeignKeyDescriptor = buildEmbeddableForeignKeyDescriptor((EmbeddableValuedModelPart) fkTarget, bootValueMapping, keyDeclaringType, collectionDescriptor.getAttributeMapping(), false, dialect, creationProcess);
attributeMapping.setForeignKeyDescriptor(embeddedForeignKeyDescriptor);
} else {
throw new NotYetImplementedFor6Exception("Support for " + fkTarget.getClass() + " foreign keys not yet implemented: " + bootValueMapping.getRole());
}
}
use of org.hibernate.metamodel.mapping.ModelPart in project hibernate-orm by hibernate.
the class AbstractDomainPath method addSortSpecification.
private void addSortSpecification(EmbeddableValuedModelPart embeddableValuedModelPart, QuerySpec ast, TableGroup tableGroup, String collation, String modelPartName, SortOrder sortOrder, NullPrecedence nullPrecedence, SqlAstCreationState creationState) {
if (embeddableValuedModelPart.getFetchableName().equals(modelPartName) || ELEMENT_TOKEN.equals(modelPartName)) {
embeddableValuedModelPart.forEachSelectable((columnIndex, selection) -> {
addSortSpecification(selection, ast, tableGroup, collation, sortOrder, nullPrecedence, creationState);
});
} else {
ModelPart subPart = embeddableValuedModelPart.findSubPart(modelPartName, null);
assert subPart instanceof BasicValuedModelPart;
addSortSpecification((BasicValuedModelPart) subPart, ast, tableGroup, collation, sortOrder, nullPrecedence, creationState);
}
}
use of org.hibernate.metamodel.mapping.ModelPart in project hibernate-orm by hibernate.
the class PluralAttributePath method resolvePathPart.
@Override
public DomainPath resolvePathPart(String name, String identifier, boolean isTerminal, TranslationContext translationContext) {
final ModelPart subPart = pluralAttributeMapping.findSubPart(name, null);
if (subPart != null) {
if (subPart instanceof CollectionPart) {
return new CollectionPartPath(this, (CollectionPart) subPart);
}
if (subPart instanceof EmbeddableValuedModelPart) {
return new DomainPathContinuation(navigablePath.append(name), this, subPart);
}
if (subPart instanceof ToOneAttributeMapping) {
return new FkDomainPathContinuation(navigablePath.append(name), this, (ToOneAttributeMapping) subPart);
}
// leaf case:
final CollectionPartPath elementPath = new CollectionPartPath(this, pluralAttributeMapping.getElementDescriptor());
return (DomainPath) elementPath.resolvePathPart(name, identifier, isTerminal, translationContext);
}
if (pluralAttributeMapping.getElementDescriptor() instanceof EmbeddableValuedModelPart) {
final EmbeddableValuedModelPart elementDescriptor = (EmbeddableValuedModelPart) pluralAttributeMapping.getElementDescriptor();
final ModelPart elementSubPart = elementDescriptor.findSubPart(name, null);
if (elementSubPart != null) {
// create the CollectionSubPath to use as the `lhs` for the element sub-path
final CollectionPartPath elementPath = new CollectionPartPath(this, (CollectionPart) elementDescriptor);
return new DomainPathContinuation(elementPath.getNavigablePath().append(name), this, elementSubPart);
}
}
if (pluralAttributeMapping.getIndexDescriptor() instanceof EmbeddableValuedModelPart) {
final EmbeddableValuedModelPart indexDescriptor = (EmbeddableValuedModelPart) pluralAttributeMapping.getIndexDescriptor();
final ModelPart indexSubPart = indexDescriptor.findSubPart(name, null);
if (indexSubPart != null) {
// create the CollectionSubPath to use as the `lhs` for the element sub-path
final CollectionPartPath indexPath = new CollectionPartPath(this, (CollectionPart) indexDescriptor);
return new DomainPathContinuation(indexPath.getNavigablePath().append(name), this, indexSubPart);
}
}
return null;
}
Aggregations