HHH-17572 Move embedded collections selection check to query validation
This commit is contained in:
parent
f88ef3e7c2
commit
b9e230e456
|
@ -15,7 +15,6 @@ import java.util.Set;
|
|||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
import org.hibernate.query.criteria.JpaOrder;
|
||||
|
@ -23,10 +22,12 @@ import org.hibernate.query.criteria.JpaPredicate;
|
|||
import org.hibernate.query.criteria.JpaQueryStructure;
|
||||
import org.hibernate.query.criteria.JpaRoot;
|
||||
import org.hibernate.query.criteria.JpaSelection;
|
||||
import org.hibernate.query.sqm.FetchClauseType;
|
||||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||
import org.hibernate.query.sqm.tree.SqmNode;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmEntityValuedSimplePath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
|
||||
|
@ -47,6 +48,7 @@ import org.hibernate.spi.NavigablePath;
|
|||
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
||||
/**
|
||||
* Defines the commonality between a root query and a subquery.
|
||||
|
@ -519,6 +521,10 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
collectSelectedFromSet( selectedFromSet, (SqmFrom<?, ?>) path.getLhs() );
|
||||
}
|
||||
}
|
||||
else if ( selectableNode instanceof SqmEmbeddedValuedSimplePath<?> ) {
|
||||
final SqmEmbeddedValuedSimplePath<?> path = (SqmEmbeddedValuedSimplePath<?>) selectableNode;
|
||||
assertEmbeddableCollections( path.getNavigablePath(), (EmbeddableDomainType<?>) path.getSqmType() );
|
||||
}
|
||||
}
|
||||
|
||||
private void collectSelectedFromSet(Set<SqmFrom<?, ?>> selectedFromSet, SqmFrom<?, ?> sqmFrom) {
|
||||
|
@ -569,6 +575,22 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
}
|
||||
}
|
||||
|
||||
private void assertEmbeddableCollections(NavigablePath navigablePath, EmbeddableDomainType<?> embeddableType) {
|
||||
if ( !embeddableType.getPluralAttributes().isEmpty() ) {
|
||||
throw new SemanticException( String.format(
|
||||
"Explicit selection of an embeddable containing associated collections is not supported: %s",
|
||||
navigablePath
|
||||
) );
|
||||
}
|
||||
else {
|
||||
for ( SingularAttribute<?, ?> attribute : embeddableType.getSingularAttributes() ) {
|
||||
if ( attribute.getType() instanceof EmbeddableDomainType<?> ) {
|
||||
assertEmbeddableCollections( navigablePath, (EmbeddableDomainType<?>) attribute.getType() );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHqlString(StringBuilder sb) {
|
||||
if ( selectClause != null ) {
|
||||
|
|
|
@ -6,10 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.SqlAstJoinType;
|
||||
import org.hibernate.sql.ast.spi.FromClauseAccess;
|
||||
|
@ -47,10 +45,6 @@ public class EmbeddableResultImpl<T> extends AbstractFetchParent implements Embe
|
|||
this.fetchContainer = modelPart.getEmbeddableTypeDescriptor();
|
||||
this.resultVariable = resultVariable;
|
||||
|
||||
// We currently don't support explicitly selecting embeddables that contain collections
|
||||
// as we wouldn't be able to correctly initialize their owning entity instances
|
||||
checkContainsCollections( modelPart, navigablePath );
|
||||
|
||||
/*
|
||||
An `{embeddable_result}` sub-path is created for the corresponding initializer to differentiate it from a fetch-initializer if this embedded is also fetched.
|
||||
The Jakarta Persistence spec says that any embedded value selected in the result should not be part of the state of any managed entity.
|
||||
|
@ -96,25 +90,6 @@ public class EmbeddableResultImpl<T> extends AbstractFetchParent implements Embe
|
|||
return false;
|
||||
}
|
||||
|
||||
private static void checkContainsCollections(
|
||||
EmbeddableValuedModelPart embeddableModelPart,
|
||||
NavigablePath navigablePath) {
|
||||
embeddableModelPart.forEachSubPart( (index, modelPart) -> {
|
||||
final AttributeMapping attribute = modelPart.asAttributeMapping();
|
||||
if ( attribute != null ) {
|
||||
if ( attribute.isPluralAttributeMapping() ) {
|
||||
throw new SemanticException( String.format(
|
||||
"Explicit selection of an embeddable containing collections is not supported: %s",
|
||||
navigablePath
|
||||
) );
|
||||
}
|
||||
else if ( attribute.isEmbeddedAttributeMapping() ) {
|
||||
checkContainsCollections( attribute.asEmbeddedAttributeMapping(), navigablePath );
|
||||
}
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getResultVariable() {
|
||||
return resultVariable;
|
||||
|
|
Loading…
Reference in New Issue