fixed fk predicate rendering into SQL AST for collections;
basic tests for loading + mapped-fetch strategy
This commit is contained in:
parent
d200fa9545
commit
3cb6e137bf
|
@ -52,7 +52,7 @@ import org.jboss.logging.Logger;
|
||||||
public class MetamodelSelectBuilderProcess {
|
public class MetamodelSelectBuilderProcess {
|
||||||
private static final Logger log = Logger.getLogger( MetamodelSelectBuilderProcess.class );
|
private static final Logger log = Logger.getLogger( MetamodelSelectBuilderProcess.class );
|
||||||
|
|
||||||
interface SqlAstDescriptor {
|
public interface SqlAstDescriptor {
|
||||||
SelectStatement getSqlAst();
|
SelectStatement getSqlAst();
|
||||||
List<JdbcParameter> getJdbcParameters();
|
List<JdbcParameter> getJdbcParameters();
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,11 @@
|
||||||
package org.hibernate.metamodel.mapping;
|
package org.hibernate.metamodel.mapping;
|
||||||
|
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.ast.JoinType;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.spi.DomainResult;
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
|
||||||
|
@ -16,4 +20,11 @@ import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
*/
|
*/
|
||||||
public interface ForeignKeyDescriptor {
|
public interface ForeignKeyDescriptor {
|
||||||
DomainResult createDomainResult(NavigablePath collectionPath, TableGroup tableGroup, DomainResultCreationState creationState);
|
DomainResult createDomainResult(NavigablePath collectionPath, TableGroup tableGroup, DomainResultCreationState creationState);
|
||||||
|
|
||||||
|
Predicate generateJoinPredicate(
|
||||||
|
TableGroup lhs,
|
||||||
|
TableGroup tableGroup,
|
||||||
|
JoinType joinType,
|
||||||
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
SqlAstCreationContext creationContext);
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,7 +40,6 @@ import org.hibernate.mapping.Selectable;
|
||||||
import org.hibernate.mapping.ToOne;
|
import org.hibernate.mapping.ToOne;
|
||||||
import org.hibernate.mapping.Value;
|
import org.hibernate.mapping.Value;
|
||||||
import org.hibernate.metamodel.CollectionClassification;
|
import org.hibernate.metamodel.CollectionClassification;
|
||||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
|
||||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||||
|
@ -647,6 +646,7 @@ public class MappingModelCreationHelper {
|
||||||
bootProperty,
|
bootProperty,
|
||||||
bootValueMapping,
|
bootValueMapping,
|
||||||
collectionDescriptor,
|
collectionDescriptor,
|
||||||
|
declaringType,
|
||||||
dialect,
|
dialect,
|
||||||
creationProcess
|
creationProcess
|
||||||
);
|
);
|
||||||
|
@ -849,14 +849,29 @@ public class MappingModelCreationHelper {
|
||||||
Property bootProperty,
|
Property bootProperty,
|
||||||
Collection bootValueMapping,
|
Collection bootValueMapping,
|
||||||
CollectionPersister collectionDescriptor,
|
CollectionPersister collectionDescriptor,
|
||||||
|
ManagedMappingType declaringType,
|
||||||
Dialect dialect,
|
Dialect dialect,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
final Type keyType = bootValueMapping.getKey().getType();
|
final Type keyType = bootValueMapping.getKey().getType();
|
||||||
|
|
||||||
|
final ModelPart fkTarget;
|
||||||
|
final String lhsPropertyName = collectionDescriptor.getCollectionType().getLHSPropertyName();
|
||||||
|
if ( lhsPropertyName == null ) {
|
||||||
|
fkTarget = collectionDescriptor.getOwnerEntityPersister().getIdentifierMapping();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fkTarget = declaringType.findAttributeMapping( lhsPropertyName );
|
||||||
|
}
|
||||||
|
|
||||||
if ( keyType instanceof BasicType ) {
|
if ( keyType instanceof BasicType ) {
|
||||||
assert bootValueMapping.getKey().getColumnSpan() == 1;
|
assert bootValueMapping.getKey().getColumnSpan() == 1;
|
||||||
|
assert fkTarget instanceof BasicValuedModelPart;
|
||||||
|
final BasicValuedModelPart simpleFkTarget = (BasicValuedModelPart) fkTarget;
|
||||||
|
|
||||||
return new SimpleForeignKeyDescriptor(
|
return new SimpleForeignKeyDescriptor(
|
||||||
bootValueMapping.getKey().getColumnIterator().next().getText( dialect ),
|
bootValueMapping.getKey().getColumnIterator().next().getText( dialect ),
|
||||||
|
simpleFkTarget.getContainingTableExpression(),
|
||||||
|
simpleFkTarget.getMappedColumnExpression(),
|
||||||
(BasicType) keyType
|
(BasicType) keyType
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -872,31 +887,24 @@ public class MappingModelCreationHelper {
|
||||||
EntityPersister referencedEntityDescriptor,
|
EntityPersister referencedEntityDescriptor,
|
||||||
Dialect dialect,
|
Dialect dialect,
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
if ( bootValueMapping.isReferenceToPrimaryKey() ) {
|
|
||||||
final EntityIdentifierMapping identifierMapping = referencedEntityDescriptor.getIdentifierMapping();
|
|
||||||
if ( identifierMapping instanceof BasicEntityIdentifierMapping ) {
|
|
||||||
final BasicEntityIdentifierMapping simpleIdMapping = (BasicEntityIdentifierMapping) identifierMapping;
|
|
||||||
|
|
||||||
assert bootValueMapping.getColumnSpan() == 1;
|
final ModelPart fkTarget;
|
||||||
return new SimpleForeignKeyDescriptor(
|
if ( bootValueMapping.isReferenceToPrimaryKey() ) {
|
||||||
bootValueMapping.getColumnIterator().next().getText( dialect ),
|
fkTarget = referencedEntityDescriptor.getIdentifierMapping();
|
||||||
simpleIdMapping.getJdbcMapping()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
final AttributeMapping attributeMapping = referencedEntityDescriptor.findAttributeMapping(
|
fkTarget = referencedEntityDescriptor.findSubPart( bootValueMapping.getReferencedPropertyName() );
|
||||||
bootValueMapping.getReferencedPropertyName()
|
}
|
||||||
);
|
|
||||||
|
|
||||||
if ( attributeMapping instanceof BasicValuedSingularAttributeMapping ) {
|
if ( fkTarget instanceof BasicValuedModelPart ) {
|
||||||
final BasicValuedSingularAttributeMapping basicMapping = (BasicValuedSingularAttributeMapping) attributeMapping;
|
final BasicValuedModelPart simpleFkTarget = (BasicValuedModelPart) fkTarget;
|
||||||
assert bootValueMapping.getColumnSpan() == 1;
|
|
||||||
return new SimpleForeignKeyDescriptor(
|
return new SimpleForeignKeyDescriptor(
|
||||||
bootValueMapping.getColumnIterator().next().getText( dialect ),
|
bootValueMapping.getColumnIterator().next().getText( dialect ),
|
||||||
basicMapping.getJdbcMapping()
|
simpleFkTarget.getContainingTableExpression(),
|
||||||
);
|
simpleFkTarget.getMappedColumnExpression(),
|
||||||
}
|
simpleFkTarget.getJdbcMapping()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new NotYetImplementedFor6Exception(
|
throw new NotYetImplementedFor6Exception(
|
||||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
|
import org.hibernate.sql.ast.tree.from.TableGroupBuilder;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||||
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
|
import org.hibernate.sql.ast.tree.from.TableReferenceCollector;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.internal.domain.collection.DelayedCollectionFetch;
|
import org.hibernate.sql.results.internal.domain.collection.DelayedCollectionFetch;
|
||||||
import org.hibernate.sql.results.internal.domain.collection.EagerCollectionFetch;
|
import org.hibernate.sql.results.internal.domain.collection.EagerCollectionFetch;
|
||||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
@ -161,9 +162,10 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
final TableGroup collectionTableGroup = sqlAstCreationState.getFromClauseAccess().resolveTableGroup(
|
final TableGroup collectionTableGroup = sqlAstCreationState.getFromClauseAccess().resolveTableGroup(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
p -> {
|
p -> {
|
||||||
|
final TableGroup lhsTableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchParent.getNavigablePath() );
|
||||||
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
|
||||||
fetchablePath,
|
fetchablePath,
|
||||||
sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchParent.getNavigablePath() ),
|
lhsTableGroup,
|
||||||
null,
|
null,
|
||||||
JoinType.LEFT,
|
JoinType.LEFT,
|
||||||
lockMode,
|
lockMode,
|
||||||
|
@ -171,6 +173,11 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
creationState.getSqlAstCreationState().getSqlExpressionResolver(),
|
creationState.getSqlAstCreationState().getSqlExpressionResolver(),
|
||||||
creationState.getSqlAstCreationState().getCreationContext()
|
creationState.getSqlAstCreationState().getCreationContext()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
lhsTableGroup.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
||||||
|
sqlAstCreationState.getFromClauseAccess().registerTableGroup( fetchablePath, tableGroupJoin.getJoinedGroup() );
|
||||||
|
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -228,7 +235,23 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme
|
||||||
creationContext
|
creationContext
|
||||||
);
|
);
|
||||||
|
|
||||||
return new TableGroupJoin( navigablePath, joinType, tableGroupBuilder.build() );
|
final TableGroup tableGroup = tableGroupBuilder.build();
|
||||||
|
final TableGroupJoin tableGroupJoin = new TableGroupJoin(
|
||||||
|
navigablePath,
|
||||||
|
joinType,
|
||||||
|
tableGroup,
|
||||||
|
getKeyDescriptor().generateJoinPredicate(
|
||||||
|
lhs,
|
||||||
|
tableGroup,
|
||||||
|
joinType,
|
||||||
|
sqlExpressionResolver,
|
||||||
|
creationContext
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
lhs.addTableGroupJoin( tableGroupJoin );
|
||||||
|
|
||||||
|
return tableGroupJoin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -8,12 +8,18 @@ package org.hibernate.metamodel.mapping.internal;
|
||||||
|
|
||||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||||
|
import org.hibernate.query.ComparisonOperator;
|
||||||
import org.hibernate.query.NavigablePath;
|
import org.hibernate.query.NavigablePath;
|
||||||
|
import org.hibernate.sql.ast.JoinType;
|
||||||
|
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||||
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
import org.hibernate.sql.ast.spi.SqlAstCreationState;
|
||||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||||
import org.hibernate.sql.ast.spi.SqlSelection;
|
import org.hibernate.sql.ast.spi.SqlSelection;
|
||||||
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
import org.hibernate.sql.ast.tree.expression.ColumnReference;
|
||||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||||
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResult;
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
|
@ -23,10 +29,18 @@ import org.hibernate.sql.results.spi.DomainResultCreationState;
|
||||||
*/
|
*/
|
||||||
public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
|
public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
private final String keyColumnExpression;
|
private final String keyColumnExpression;
|
||||||
|
private final String targetColumnContainingTable;
|
||||||
|
private final String targetColumnExpression;
|
||||||
private final JdbcMapping jdbcMapping;
|
private final JdbcMapping jdbcMapping;
|
||||||
|
|
||||||
public SimpleForeignKeyDescriptor(String keyColumnExpression, JdbcMapping jdbcMapping) {
|
public SimpleForeignKeyDescriptor(
|
||||||
|
String keyColumnExpression,
|
||||||
|
String targetColumnContainingTable,
|
||||||
|
String targetColumnExpression,
|
||||||
|
JdbcMapping jdbcMapping) {
|
||||||
this.keyColumnExpression = keyColumnExpression;
|
this.keyColumnExpression = keyColumnExpression;
|
||||||
|
this.targetColumnContainingTable = targetColumnContainingTable;
|
||||||
|
this.targetColumnExpression = targetColumnExpression;
|
||||||
this.jdbcMapping = jdbcMapping;
|
this.jdbcMapping = jdbcMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,4 +75,43 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
jdbcMapping.getJavaTypeDescriptor()
|
jdbcMapping.getJavaTypeDescriptor()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Predicate generateJoinPredicate(
|
||||||
|
TableGroup lhs,
|
||||||
|
TableGroup tableGroup,
|
||||||
|
JoinType joinType,
|
||||||
|
SqlExpressionResolver sqlExpressionResolver,
|
||||||
|
SqlAstCreationContext creationContext) {
|
||||||
|
final TableReference tableReference = lhs.resolveTableReference( targetColumnContainingTable );
|
||||||
|
|
||||||
|
final ColumnReference targetReference = (ColumnReference) sqlExpressionResolver.resolveSqlExpression(
|
||||||
|
SqlExpressionResolver.createColumnReferenceKey( tableReference, keyColumnExpression ),
|
||||||
|
s -> new ColumnReference(
|
||||||
|
tableReference.getIdentificationVariable(),
|
||||||
|
targetColumnExpression,
|
||||||
|
jdbcMapping,
|
||||||
|
creationContext.getSessionFactory()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
final ColumnReference keyReference = (ColumnReference) sqlExpressionResolver.resolveSqlExpression(
|
||||||
|
SqlExpressionResolver.createColumnReferenceKey(
|
||||||
|
tableGroup.getPrimaryTableReference(),
|
||||||
|
keyColumnExpression
|
||||||
|
),
|
||||||
|
s -> new ColumnReference(
|
||||||
|
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
|
||||||
|
keyColumnExpression,
|
||||||
|
jdbcMapping,
|
||||||
|
creationContext.getSessionFactory()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
return new ComparisonPredicate(
|
||||||
|
targetReference,
|
||||||
|
ComparisonOperator.EQUAL,
|
||||||
|
keyReference
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6150,7 +6150,6 @@ public abstract class AbstractEntityPersister
|
||||||
runtimeAttrDefinition,
|
runtimeAttrDefinition,
|
||||||
bootProperty,
|
bootProperty,
|
||||||
stateArrayPosition++,
|
stateArrayPosition++,
|
||||||
this,
|
|
||||||
creationProcess
|
creationProcess
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
@ -6311,7 +6310,6 @@ public abstract class AbstractEntityPersister
|
||||||
NonIdentifierAttribute tupleAttrDefinition,
|
NonIdentifierAttribute tupleAttrDefinition,
|
||||||
Property bootProperty,
|
Property bootProperty,
|
||||||
int stateArrayPosition,
|
int stateArrayPosition,
|
||||||
ManagedMappingType declaringType,
|
|
||||||
MappingModelCreationProcess creationProcess) {
|
MappingModelCreationProcess creationProcess) {
|
||||||
|
|
||||||
final String attrName = tupleAttrDefinition.getName();
|
final String attrName = tupleAttrDefinition.getName();
|
||||||
|
@ -6333,7 +6331,7 @@ public abstract class AbstractEntityPersister
|
||||||
attrName,
|
attrName,
|
||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
bootProperty,
|
bootProperty,
|
||||||
declaringType,
|
this,
|
||||||
(BasicType) attrType,
|
(BasicType) attrType,
|
||||||
tableExpression,
|
tableExpression,
|
||||||
attrColumnNames[0],
|
attrColumnNames[0],
|
||||||
|
@ -6347,7 +6345,7 @@ public abstract class AbstractEntityPersister
|
||||||
attrName,
|
attrName,
|
||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
bootProperty,
|
bootProperty,
|
||||||
declaringType,
|
this,
|
||||||
(CompositeType) attrType,
|
(CompositeType) attrType,
|
||||||
tableExpression,
|
tableExpression,
|
||||||
attrColumnNames,
|
attrColumnNames,
|
||||||
|
@ -6361,7 +6359,7 @@ public abstract class AbstractEntityPersister
|
||||||
attrName,
|
attrName,
|
||||||
stateArrayPosition,
|
stateArrayPosition,
|
||||||
bootProperty,
|
bootProperty,
|
||||||
declaringType,
|
this,
|
||||||
propertyAccess,
|
propertyAccess,
|
||||||
tupleAttrDefinition.getCascadeStyle(),
|
tupleAttrDefinition.getCascadeStyle(),
|
||||||
creationProcess
|
creationProcess
|
||||||
|
|
|
@ -1015,7 +1015,9 @@ public abstract class AbstractSqlAstWalker
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
comparisonPredicate.getLeftHandExpression().accept( this );
|
comparisonPredicate.getLeftHandExpression().accept( this );
|
||||||
|
appendSql( " " );
|
||||||
appendSql( comparisonPredicate.getOperator().sqlText() );
|
appendSql( comparisonPredicate.getOperator().sqlText() );
|
||||||
|
appendSql( " " );
|
||||||
comparisonPredicate.getRightHandExpression().accept( this );
|
comparisonPredicate.getRightHandExpression().accept( this );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* Hibernate, Relational Persistence for Idiomatic Java
|
||||||
|
*
|
||||||
|
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||||
|
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||||
|
*/
|
||||||
|
package org.hibernate.orm.test.loading;
|
||||||
|
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.persistence.CollectionTable;
|
||||||
|
import javax.persistence.ElementCollection;
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.FetchType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.JoinColumn;
|
||||||
|
import javax.persistence.OneToMany;
|
||||||
|
import javax.persistence.Table;
|
||||||
|
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.LockOptions;
|
||||||
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
|
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||||
|
import org.hibernate.loader.internal.MetamodelSelectBuilderProcess;
|
||||||
|
import org.hibernate.metamodel.spi.DomainMetamodel;
|
||||||
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||||
|
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||||
|
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
|
||||||
|
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||||
|
import org.hibernate.sql.results.internal.domain.basic.BasicFetch;
|
||||||
|
import org.hibernate.sql.results.internal.domain.collection.DelayedCollectionFetch;
|
||||||
|
import org.hibernate.sql.results.internal.domain.collection.EagerCollectionFetch;
|
||||||
|
import org.hibernate.sql.results.spi.DomainResult;
|
||||||
|
import org.hibernate.sql.results.spi.EntityResult;
|
||||||
|
import org.hibernate.sql.results.spi.Fetch;
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
import org.hamcrest.CoreMatchers;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Steve Ebersole
|
||||||
|
*/
|
||||||
|
@DomainModel(
|
||||||
|
annotatedClasses = {
|
||||||
|
MappedFetchTests.RootEntity.class,
|
||||||
|
MappedFetchTests.SimpleEntity.class
|
||||||
|
}
|
||||||
|
)
|
||||||
|
@SessionFactory
|
||||||
|
@SuppressWarnings("WeakerAccess")
|
||||||
|
public class MappedFetchTests {
|
||||||
|
@Test
|
||||||
|
public void baseline(SessionFactoryScope scope) {
|
||||||
|
final SessionFactoryImplementor sessionFactory = scope.getSessionFactory();
|
||||||
|
final DomainMetamodel domainModel = sessionFactory.getDomainModel();
|
||||||
|
final EntityPersister rootEntityDescriptor = domainModel.getEntityDescriptor( RootEntity.class );
|
||||||
|
final MetamodelSelectBuilderProcess.SqlAstDescriptor sqlAstDescriptor = MetamodelSelectBuilderProcess.createSelect(
|
||||||
|
sessionFactory,
|
||||||
|
rootEntityDescriptor,
|
||||||
|
null,
|
||||||
|
rootEntityDescriptor.getIdentifierMapping(),
|
||||||
|
null,
|
||||||
|
1,
|
||||||
|
LoadQueryInfluencers.NONE,
|
||||||
|
LockOptions.NONE
|
||||||
|
);
|
||||||
|
|
||||||
|
assertThat( sqlAstDescriptor.getSqlAst().getDomainResultDescriptors().size(), is( 1 ) );
|
||||||
|
|
||||||
|
final DomainResult domainResult = sqlAstDescriptor.getSqlAst().getDomainResultDescriptors().get( 0 );
|
||||||
|
assertThat( domainResult, instanceOf( EntityResult.class ) );
|
||||||
|
|
||||||
|
final EntityResult entityResult = (EntityResult) domainResult;
|
||||||
|
final List<Fetch> fetches = entityResult.getFetches();
|
||||||
|
|
||||||
|
// name + both lists
|
||||||
|
assertThat( fetches.size(), is( 3 ) );
|
||||||
|
|
||||||
|
// order is alphabetical...
|
||||||
|
|
||||||
|
final Fetch nameFetch = fetches.get( 0 );
|
||||||
|
assertThat( nameFetch.getFetchedMapping().getFetchableName(), is( "name" ) );
|
||||||
|
assertThat( nameFetch, instanceOf( BasicFetch.class ) );
|
||||||
|
|
||||||
|
final Fetch nickNamesFetch = fetches.get( 1 );
|
||||||
|
assertThat( nickNamesFetch.getFetchedMapping().getFetchableName(), is( "nickNames" ) );
|
||||||
|
assertThat( nickNamesFetch, instanceOf( EagerCollectionFetch.class ) );
|
||||||
|
|
||||||
|
final Fetch simpleEntitiesFetch = fetches.get( 2 );
|
||||||
|
assertThat( simpleEntitiesFetch.getFetchedMapping().getFetchableName(), is( "simpleEntities" ) );
|
||||||
|
assertThat( simpleEntitiesFetch, instanceOf( DelayedCollectionFetch.class ) );
|
||||||
|
|
||||||
|
|
||||||
|
final QuerySpec querySpec = sqlAstDescriptor.getSqlAst().getQuerySpec();
|
||||||
|
|
||||||
|
final TableGroup tableGroup = querySpec.getFromClause().getRoots().get( 0 );
|
||||||
|
assertThat( tableGroup.getModelPart(), is( rootEntityDescriptor ) );
|
||||||
|
assertThat( tableGroup.getTableGroupJoins().size(), is( 1 ) );
|
||||||
|
|
||||||
|
final TableGroupJoin collectionJoin = tableGroup.getTableGroupJoins().iterator().next();
|
||||||
|
assertThat( collectionJoin.getJoinedGroup().getModelPart(), is( nickNamesFetch.getFetchedMapping() ) );
|
||||||
|
|
||||||
|
assertThat( collectionJoin.getPredicate(), notNullValue() );
|
||||||
|
assertThat( collectionJoin.getPredicate(), instanceOf( ComparisonPredicate.class ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void smokeTest(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final RootEntity first = session.get( RootEntity.class, 1 );
|
||||||
|
assertThat( Hibernate.isInitialized( first ), is( true ) );
|
||||||
|
|
||||||
|
assertThat( Hibernate.isInitialized( first.getNickNames() ), is( true ) );
|
||||||
|
assertThat( first.getNickNames().size(), is( 2 ) );
|
||||||
|
|
||||||
|
assertThat( Hibernate.isInitialized( first.getSimpleEntities() ), is( false ) );
|
||||||
|
|
||||||
|
final RootEntity second = session.get( RootEntity.class, 2 );
|
||||||
|
assertThat( Hibernate.isInitialized( second ), is( true ) );
|
||||||
|
|
||||||
|
assertThat( Hibernate.isInitialized( second.getNickNames() ), is( true ) );
|
||||||
|
assertThat( second.getNickNames().size(), is( 2 ) );
|
||||||
|
|
||||||
|
assertThat( Hibernate.isInitialized( second.getSimpleEntities() ), is( false ) );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
public void createTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> {
|
||||||
|
final RootEntity root1 = new RootEntity( 1, "first" );
|
||||||
|
root1.addNickName( "1st" );
|
||||||
|
root1.addNickName( "primo" );
|
||||||
|
session.save( root1 );
|
||||||
|
|
||||||
|
final RootEntity root2 = new RootEntity( 2, "second" );
|
||||||
|
root2.addNickName( "2nd" );
|
||||||
|
root2.addNickName( "first loser" );
|
||||||
|
session.save( root2 );
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void dropTestData(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(
|
||||||
|
session -> session.doWork(
|
||||||
|
connection -> {
|
||||||
|
try ( Statement statement = connection.createStatement() ) {
|
||||||
|
statement.execute( "delete nick_names" );
|
||||||
|
statement.execute( "delete simple_entity" );
|
||||||
|
statement.execute( "delete root_entity" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "RootEntity" )
|
||||||
|
@Table( name = "root_entity" )
|
||||||
|
public static class RootEntity {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private List<String> nickNames;
|
||||||
|
private List<SimpleEntity> simpleEntities;
|
||||||
|
|
||||||
|
public RootEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public RootEntity(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@ElementCollection( fetch = FetchType.EAGER )
|
||||||
|
@CollectionTable( name = "nick_names" )
|
||||||
|
public List<String> getNickNames() {
|
||||||
|
return nickNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setNickNames(List<String> nickNames) {
|
||||||
|
this.nickNames = nickNames;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addNickName(String name) {
|
||||||
|
if ( nickNames == null ) {
|
||||||
|
nickNames = new ArrayList<>();
|
||||||
|
}
|
||||||
|
nickNames.add( name );
|
||||||
|
}
|
||||||
|
|
||||||
|
@OneToMany( fetch = FetchType.LAZY )
|
||||||
|
@JoinColumn( name = "simple_id" )
|
||||||
|
public List<SimpleEntity> getSimpleEntities() {
|
||||||
|
return simpleEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setSimpleEntities(List<SimpleEntity> simpleEntities) {
|
||||||
|
this.simpleEntities = simpleEntities;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addSimpleEntity(SimpleEntity simpleEntity) {
|
||||||
|
if ( simpleEntities == null ) {
|
||||||
|
simpleEntities = new ArrayList<>();
|
||||||
|
}
|
||||||
|
simpleEntities.add( simpleEntity );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Entity( name = "SimpleEntity" )
|
||||||
|
@Table( name = "simple_entity" )
|
||||||
|
public static class SimpleEntity {
|
||||||
|
private Integer id;
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
public SimpleEntity() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public SimpleEntity(Integer id, String name) {
|
||||||
|
this.id = id;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Id
|
||||||
|
public Integer getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(Integer id) {
|
||||||
|
this.id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setName(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue