Fix @manyToMany member of query

This commit is contained in:
Andrea Boriero 2020-08-06 12:59:42 +01:00
parent bd3775b114
commit 7e87deb349
10 changed files with 65 additions and 79 deletions

View File

@ -20,6 +20,10 @@ public class AssociationKey {
this.columns = columns;
}
public String getTable() {
return table;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {

View File

@ -166,10 +166,9 @@ public class EntityCollectionPart
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
return fkTargetModelPart.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
}
@Override
public void visitColumns(ColumnConsumer consumer) {
entityMappingType.visitColumns( consumer );

View File

@ -29,6 +29,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
import org.hibernate.metamodel.mapping.CollectionMappingType;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.ColumnConsumer;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;

View File

@ -83,6 +83,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
private ForeignKeyDescriptor foreignKeyDescriptor;
private ForeignKeyDirection foreignKeyDirection;
private String identifyingColumnsTableExpression;
private boolean isKeyReferringSide;
public ToOneAttributeMapping(
String name,
@ -184,6 +185,8 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
this.foreignKeyDescriptor = foreignKeyDescriptor;
assert identifyingColumnsTableExpression != null;
isKeyReferringSide = foreignKeyDescriptor.getAssociationKey().getTable().equals( identifyingColumnsTableExpression );
}
public void setIdentifyingColumnsTableExpression(String tableExpression) {
@ -310,7 +313,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
We have a cirularity but it is not bidirectional
*/
if ( referringPrimaryKey ) {
if ( isKeyReferringSide ) {
final TableGroup parentTableGroup = creationState
.getSqlAstCreationState()
.getFromClauseAccess()
@ -462,13 +465,13 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
*/
boolean selectByUniqueKey;
if ( referringPrimaryKey ) {
if ( isKeyReferringSide ) {
// case 1.2
keyResult = foreignKeyDescriptor.createDomainResult( fetchablePath, parentTableGroup, creationState );
selectByUniqueKey = false;
}
else {
keyResult = ((EntityPersister) getDeclaringType()).getIdentifierMapping()
keyResult = ( (EntityPersister) getDeclaringType() ).getIdentifierMapping()
.createDomainResult( fetchablePath, parentTableGroup, null, creationState );
// case 1.1
selectByUniqueKey = true;
@ -616,7 +619,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping
@Override
public void visitColumns(ColumnConsumer consumer) {
if ( foreignKeyDirection == ForeignKeyDirection.FROM_PARENT ) {
if ( isKeyReferringSide ) {
foreignKeyDescriptor.visitReferringColumns( consumer );
}
}

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.query.sqm.mutation.internal;
import java.util.Collections;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
@ -30,7 +29,6 @@ import org.hibernate.query.sqm.tree.select.SqmSelectClause;
import org.hibernate.query.sqm.tree.update.SqmAssignment;
import org.hibernate.query.sqm.tree.update.SqmSetClause;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
@ -41,9 +39,6 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.update.Assignable;
import org.hibernate.sql.ast.tree.update.Assignment;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
/**
* Specialized BaseSqmToSqlAstConverter implementation used during conversion
@ -56,7 +51,7 @@ import org.hibernate.sql.results.graph.FetchParent;
*
* @author Steve Ebersole
*/
public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter implements DomainResultCreationState {
public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter {
private final EntityMappingType mutatingEntityDescriptor;
private final TableGroup mutatingTableGroup;
@ -212,16 +207,6 @@ public class MultiTableSqmMutationConverter extends BaseSqmToSqlAstConverter imp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@Override
public SqlAstCreationState getSqlAstCreationState() {
return this;
}
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
return Collections.emptyList();
}
public void visitSelectClause(
SqmSelectClause sqmSelectClause,
QuerySpec sqlQuerySpec,

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.sql;
import java.util.ArrayList;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@ -21,12 +22,10 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.dialect.function.TimestampaddFunction;
import org.hibernate.dialect.function.TimestampdiffFunction;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.MutableInteger;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.ColumnConsumer;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
@ -137,6 +136,7 @@ import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
import org.hibernate.sql.ast.spi.SqlAstQuerySpecProcessingState;
import org.hibernate.sql.ast.spi.SqlAstTreeHelper;
@ -150,7 +150,6 @@ import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression;
import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression;
import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression;
import org.hibernate.sql.ast.tree.expression.CastTarget;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit;
@ -185,7 +184,9 @@ import org.hibernate.sql.ast.tree.select.SortSpecification;
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
import org.hibernate.sql.exec.internal.JdbcParametersImpl;
import org.hibernate.sql.exec.spi.JdbcParameters;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
@ -204,7 +205,7 @@ import static org.hibernate.type.spi.TypeConfiguration.isDuration;
*/
public abstract class BaseSqmToSqlAstConverter
extends BaseSemanticQueryWalker
implements SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, FromClauseAccess {
implements SqmToSqlAstConverter, JdbcParameterBySqmParameterAccess, FromClauseAccess, DomainResultCreationState {
private static final Logger log = Logger.getLogger( BaseSqmToSqlAstConverter.class );
@ -2213,6 +2214,15 @@ public abstract class BaseSqmToSqlAstConverter
private QuerySpec createMemberOfSubQuery(SqmPath<?> pluralPath, PluralAttributeMapping mappingModelExpressable) {
final QuerySpec querySpec = new QuerySpec( true );
processingStateStack.push(
new SqlAstQuerySpecProcessingStateImpl(
querySpec,
processingStateStack.getCurrent(),
this,
currentClauseStack::getCurrent
)
);
final TableGroup rootTableGroup = mappingModelExpressable.createRootTableGroup(
pluralPath.getNavigablePath(),
null,
@ -2223,22 +2233,17 @@ public abstract class BaseSqmToSqlAstConverter
() -> querySpec::applyPredicate,
creationContext
);
querySpec.getFromClause().addRoot( rootTableGroup );
final CollectionPart elementDescriptor = mappingModelExpressable.getElementDescriptor();
final ColumnConsumer columnConsumer = createMemberOfColumnConsumer( querySpec, rootTableGroup );
if ( elementDescriptor instanceof EntityCollectionPart ) {
( (EntityCollectionPart) elementDescriptor ).getEntityMappingType()
.getIdentifierMapping().visitColumns( columnConsumer );
}
else if ( elementDescriptor instanceof BasicValuedCollectionPart ) {
elementDescriptor.visitColumns( columnConsumer );
}
else {
throw new NotYetImplementedFor6Exception(
"Member of with Collection of Embeddable has not yet been implemented" );
}
elementDescriptor.createDomainResult(
pluralPath.getNavigablePath(),
rootTableGroup,
null,
this
);
final Predicate predicate = mappingModelExpressable.getKeyDescriptor().generateJoinPredicate(
getFromClauseAccess().findTableGroup( pluralPath.getNavigablePath().getParent() ),
@ -2249,28 +2254,10 @@ public abstract class BaseSqmToSqlAstConverter
);
querySpec.applyPredicate( predicate );
processingStateStack.pop();
return querySpec;
}
private ColumnConsumer createMemberOfColumnConsumer(QuerySpec querySpec, TableGroup rootTableGroup) {
final MutableInteger count = new MutableInteger();
return (containingTableExpression, columnExpression, isColumnExpressionFormula, jdbcMapping) -> {
ColumnReference columnReference = new ColumnReference(
rootTableGroup.getPrimaryTableReference(),
columnExpression,
isColumnExpressionFormula,
jdbcMapping,
creationContext.getSessionFactory()
);
final int valuesPosition = count.getAndIncrement();
querySpec.getSelectClause().addSqlSelection(
new SqlSelectionImpl( valuesPosition + 1, valuesPosition, columnReference )
);
};
}
@Override
public NegatedPredicate visitNegatedPredicate(SqmNegatedPredicate predicate) {
return new NegatedPredicate(
@ -2453,4 +2440,14 @@ public abstract class BaseSqmToSqlAstConverter
public Object visitExistsPredicate(SqmExistsPredicate predicate) {
return new ExistsPredicate( (QuerySpec) predicate.getExpression().accept( this ) );
}
@Override
public SqlAstCreationState getSqlAstCreationState() {
return this;
}
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
return Collections.emptyList();
}
}

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.query.sqm.sql.internal;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.internal.util.collections.CollectionHelper;
@ -27,7 +29,6 @@ import org.hibernate.query.sqm.tree.insert.SqmValues;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.cte.CteStatement;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -37,19 +38,13 @@ import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.ast.tree.update.Assignable;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import java.util.Collections;
import java.util.List;
/**
* @author Steve Ebersole
*/
public class StandardSqmInsertTranslator
extends BaseSqmToSqlAstConverter
implements SqmInsertTranslator, DomainResultCreationState {
implements SqmInsertTranslator {
private final List<DomainResult> domainResults = CollectionHelper.arrayList( 10 );
@ -229,13 +224,4 @@ public class StandardSqmInsertTranslator
return new SelectStatement( querySpec, domainResults );
}
@Override
public SqlAstCreationState getSqlAstCreationState() {
return this;
}
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
return Collections.emptyList();
}
}

View File

@ -73,7 +73,6 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.EntityGraphTraversalState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
@ -93,7 +92,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@SuppressWarnings("unchecked")
public class StandardSqmSelectTranslator
extends BaseSqmToSqlAstConverter
implements DomainResultCreationState, SqmSelectTranslator {
implements SqmSelectTranslator {
// prepare for 10 root selections to avoid list growth in most cases
private final List<DomainResult> domainResults = CollectionHelper.arrayList( 10 );

View File

@ -56,7 +56,6 @@ public class StandardSqmUpdateTranslator
extends BaseSqmToSqlAstConverter
implements SimpleSqmUpdateTranslator {
public StandardSqmUpdateTranslator(
SqlAstCreationContext creationContext,
QueryOptions queryOptions,
@ -292,4 +291,5 @@ public class StandardSqmUpdateTranslator
return assignments;
}
}

View File

@ -31,6 +31,7 @@ import javax.persistence.TemporalType;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@ -104,6 +105,17 @@ public class ManyToManyHqlMemberOfQueryTest {
);
}
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery( "delete from Call" ).executeUpdate();
session.createQuery( "delete from Person" ).executeUpdate();
session.createQuery( "delete from Phone" ).executeUpdate();
}
);
}
@Test
public void testMemberOf(SessionFactoryScope scope) {
scope.inTransaction(
@ -155,7 +167,7 @@ public class ManyToManyHqlMemberOfQueryTest {
@Temporal(TemporalType.TIMESTAMP)
private Date createdOn;
@ManyToMany( cascade = CascadeType.ALL)
@ManyToMany(cascade = CascadeType.ALL)
private List<Phone> phones = new ArrayList<>();
@ElementCollection