ResultSet mapping
- Support for implicit and mixed attribute mappings for `@EntityResult`
This commit is contained in:
parent
b744d7891c
commit
b7eed1842c
|
@ -34,6 +34,7 @@ import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping
|
|||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.internal.FetchMementoBasicStandard;
|
||||
import org.hibernate.query.internal.ImplicitModelPartResultMemento;
|
||||
import org.hibernate.query.internal.ModelPartResultMementoBasicImpl;
|
||||
import org.hibernate.query.internal.NamedResultSetMappingMementoImpl;
|
||||
import org.hibernate.query.internal.ResultMementoBasicStandard;
|
||||
|
@ -46,6 +47,7 @@ import org.hibernate.query.named.NamedResultSetMappingMemento;
|
|||
import org.hibernate.query.named.ResultMemento;
|
||||
import org.hibernate.query.named.ResultMementoBasic;
|
||||
import org.hibernate.query.named.ResultMementoInstantiation.ArgumentMemento;
|
||||
import org.hibernate.query.results.ResultsHelper;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
|
@ -271,9 +273,6 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
|
||||
final EntityMappingType entityDescriptor = runtimeMetamodels.getEntityMappingType( entityName );
|
||||
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
|
||||
final String identifierAttributeName = identifierMapping instanceof SingleAttributeIdentifierMapping
|
||||
? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName()
|
||||
: EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
|
||||
final MutableObject<ResultMemento> identifierMementoReference = new MutableObject<>();
|
||||
|
||||
|
@ -284,30 +283,65 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
|
|||
);
|
||||
|
||||
final Map<String, FetchMemento> fetchMementos = new HashMap<>();
|
||||
fetchMappings.forEach(
|
||||
(attrName, attrMapping) -> {
|
||||
if ( EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( attrName )
|
||||
|| identifierAttributeName.equals( attrName ) ) {
|
||||
|
||||
|
||||
entityDescriptor.visitAttributeMappings(
|
||||
attributeMapping -> {
|
||||
final String fetchableName = attributeMapping.getFetchableName();
|
||||
final String attrNameName = attributeMapping.getAttributeName();
|
||||
|
||||
final boolean isIdentifier = ResultsHelper.isIdentifier(
|
||||
identifierMapping,
|
||||
fetchableName,
|
||||
attrNameName
|
||||
);
|
||||
|
||||
final AttributeFetchDescriptor fetchDescriptor = fetchMappings.get( fetchableName );
|
||||
|
||||
if ( isIdentifier ) {
|
||||
final ResultMemento idResultMemento;
|
||||
|
||||
final EntityIdentifierNavigablePath idPath = new EntityIdentifierNavigablePath( navigablePath );
|
||||
identifierMementoReference.set( attrMapping.asResultMemento( idPath, resolutionContext ) );
|
||||
if ( fetchDescriptor == null ) {
|
||||
final AttributeFetchDescriptor idRoleFetchDescriptor = fetchMappings.get( EntityIdentifierMapping.ROLE_LOCAL_NAME );
|
||||
if ( idRoleFetchDescriptor == null ) {
|
||||
idResultMemento = ResultsHelper.implicitIdentifierResult( identifierMapping, idPath, resolutionContext );
|
||||
}
|
||||
else {
|
||||
idResultMemento = idRoleFetchDescriptor.asResultMemento( idPath, resolutionContext );
|
||||
}
|
||||
}
|
||||
else {
|
||||
idResultMemento = fetchDescriptor.asResultMemento( idPath, resolutionContext );
|
||||
}
|
||||
|
||||
identifierMementoReference.set( idResultMemento );
|
||||
}
|
||||
else {
|
||||
fetchMementos.put( attrName, attrMapping.resolve( resolutionContext ) );
|
||||
final NavigablePath fetchPath = navigablePath.append( fetchableName );
|
||||
|
||||
final FetchMemento fetchMemento;
|
||||
if ( fetchDescriptor == null ) {
|
||||
fetchMemento = ResultsHelper.implicitFetch( attributeMapping, fetchPath, resolutionContext );
|
||||
}
|
||||
else {
|
||||
fetchMemento = fetchDescriptor.resolve( resolutionContext );
|
||||
}
|
||||
|
||||
fetchMementos.put( fetchableName, fetchMemento );
|
||||
}
|
||||
}
|
||||
},
|
||||
null
|
||||
);
|
||||
|
||||
if ( identifierMementoReference.isNotSet() ) {
|
||||
throw new IllegalStateException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Entity identifier mapping not specified for @EntityResult(%s) for ResultSet mapping `%s`",
|
||||
entityDescriptor.getEntityName(),
|
||||
resultSetMappingName
|
||||
)
|
||||
);
|
||||
final EntityIdentifierNavigablePath idPath = new EntityIdentifierNavigablePath( navigablePath );
|
||||
identifierMementoReference.set( new ImplicitModelPartResultMemento( idPath, identifierMapping ) );
|
||||
}
|
||||
|
||||
assert entityDescriptor.getNumberOfAttributeMappings() == fetchMementos.size();
|
||||
assert identifierMementoReference.isSet();
|
||||
|
||||
return new ResultMementoEntityStandard(
|
||||
entityDescriptor,
|
||||
LockMode.READ,
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
import org.hibernate.property.access.spi.PropertyAccess;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
|
||||
/**
|
||||
* Describes an attribute at the mapping model level.
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface AttributeMapping extends ModelPart, ValueMapping {
|
||||
public interface AttributeMapping extends ModelPart, ValueMapping, Fetchable {
|
||||
String getAttributeName();
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.query.internal;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.MappingType;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.named.FetchMemento;
|
||||
import org.hibernate.query.results.FetchBuilder;
|
||||
import org.hibernate.query.results.ImplicitAttributeFetchBuilder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ImplicitAttributeFetchMemento implements FetchMemento {
|
||||
private final NavigablePath navigablePath;
|
||||
private final AttributeMapping attributeMapping;
|
||||
|
||||
public ImplicitAttributeFetchMemento(NavigablePath navigablePath, AttributeMapping attributeMapping) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.attributeMapping = attributeMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MappingType getMappingType() {
|
||||
return attributeMapping.getPartMappingType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public FetchBuilder resolve(
|
||||
Parent parent,
|
||||
Consumer<String> querySpaceConsumer,
|
||||
ResultSetMappingResolutionContext context) {
|
||||
return new ImplicitAttributeFetchBuilder( navigablePath, attributeMapping );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AttributeMapping getReferencedModelPart() {
|
||||
return attributeMapping;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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.query.internal;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.named.ModelPartResultMemento;
|
||||
import org.hibernate.query.named.ModelPartResultMementoBasic;
|
||||
import org.hibernate.query.results.ImplicitModelPartResultBuilder;
|
||||
import org.hibernate.query.results.ResultBuilder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ImplicitModelPartResultMemento implements ModelPartResultMemento {
|
||||
private final NavigablePath navigablePath;
|
||||
private final ModelPart referencedModelPart;
|
||||
|
||||
public ImplicitModelPartResultMemento(NavigablePath navigablePath, ModelPart referencedModelPart) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.referencedModelPart = referencedModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPart getReferencedModelPart() {
|
||||
return referencedModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultBuilder resolve(
|
||||
Consumer<String> querySpaceConsumer,
|
||||
ResultSetMappingResolutionContext context) {
|
||||
return new ImplicitModelPartResultBuilder(
|
||||
navigablePath,
|
||||
null,
|
||||
referencedModelPart
|
||||
);
|
||||
}
|
||||
}
|
|
@ -34,6 +34,7 @@ import org.hibernate.sql.results.ResultsLogger;
|
|||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
|
@ -47,8 +48,9 @@ public class DomainResultCreationStateImpl
|
|||
private final String stateIdentifier;
|
||||
private final FromClauseAccessImpl fromClauseAccess;
|
||||
|
||||
private final JdbcValuesMetadata jdbcResultsMetadata;
|
||||
private final Consumer<SqlSelection> sqlSelectionConsumer;
|
||||
private final Map<String,SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
|
||||
private final Map<String, SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
|
||||
private boolean allowPositionalSelections = true;
|
||||
|
||||
private final SqlAliasBaseManager sqlAliasBaseManager;
|
||||
|
@ -59,10 +61,12 @@ public class DomainResultCreationStateImpl
|
|||
|
||||
public DomainResultCreationStateImpl(
|
||||
String stateIdentifier,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
Map<String, Map<String, DynamicFetchBuilderLegacy>> legacyFetchBuilders,
|
||||
Consumer<SqlSelection> sqlSelectionConsumer,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
this.stateIdentifier = stateIdentifier;
|
||||
this.jdbcResultsMetadata = jdbcResultsMetadata;
|
||||
this.sqlSelectionConsumer = sqlSelectionConsumer;
|
||||
this.fromClauseAccess = new FromClauseAccessImpl();
|
||||
this.sqlAliasBaseManager = new SqlAliasBaseManager();
|
||||
|
@ -93,6 +97,11 @@ public class DomainResultCreationStateImpl
|
|||
this.allowPositionalSelections = false;
|
||||
}
|
||||
|
||||
public JdbcValuesMetadata getJdbcResultsMetadata() {
|
||||
return jdbcResultsMetadata;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// DomainResultCreationState
|
||||
|
||||
|
@ -200,14 +209,19 @@ public class DomainResultCreationStateImpl
|
|||
}
|
||||
else if ( created instanceof ColumnReference ) {
|
||||
final ColumnReference columnReference = (ColumnReference) created;
|
||||
final String columnExpression = columnReference.getColumnExpression();
|
||||
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnExpression );
|
||||
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
|
||||
|
||||
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl(
|
||||
sqlSelectionMap.size() + 1,
|
||||
valuesArrayPosition,
|
||||
columnReference.getJdbcMapping()
|
||||
);
|
||||
|
||||
sqlSelectionMap.put( key, sqlSelection );
|
||||
sqlSelectionConsumer.accept( sqlSelection );
|
||||
|
||||
return sqlSelection;
|
||||
}
|
||||
|
||||
return created;
|
||||
|
@ -218,6 +232,9 @@ public class DomainResultCreationStateImpl
|
|||
Expression expression,
|
||||
JavaTypeDescriptor javaTypeDescriptor,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
if ( expression == null ) {
|
||||
throw new IllegalArgumentException( "Expression cannot be null" );
|
||||
}
|
||||
assert expression instanceof SqlSelectionImpl;
|
||||
return (SqlSelection) expression;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
/*
|
||||
* 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.query.results;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.FetchTiming;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
* FetchBuilder used when an explicit mapping was not given
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ImplicitAttributeFetchBuilder implements FetchBuilder {
|
||||
private final NavigablePath navigablePath;
|
||||
private final AttributeMapping attributeMapping;
|
||||
|
||||
public ImplicitAttributeFetchBuilder(NavigablePath navigablePath, AttributeMapping attributeMapping) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.attributeMapping = attributeMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Fetch buildFetch(
|
||||
FetchParent parent,
|
||||
NavigablePath fetchPath,
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
|
||||
DomainResultCreationState domainResultCreationState) {
|
||||
assert fetchPath.equals( navigablePath );
|
||||
|
||||
return attributeMapping.generateFetch(
|
||||
parent,
|
||||
fetchPath,
|
||||
FetchTiming.IMMEDIATE,
|
||||
true,
|
||||
LockMode.READ,
|
||||
null,
|
||||
domainResultCreationState
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* 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.query.results;
|
||||
|
||||
import java.util.function.BiFunction;
|
||||
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ImplicitModelPartResultBuilder implements ResultBuilder {
|
||||
private final NavigablePath navigablePath;
|
||||
private final String alias;
|
||||
private final ModelPart referencedModelPart;
|
||||
|
||||
public ImplicitModelPartResultBuilder(
|
||||
NavigablePath navigablePath,
|
||||
String alias,
|
||||
ModelPart referencedModelPart) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.alias = alias;
|
||||
this.referencedModelPart = referencedModelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DomainResult<?> buildResult(
|
||||
JdbcValuesMetadata jdbcResultsMetadata,
|
||||
int resultPosition,
|
||||
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
|
||||
DomainResultCreationState domainResultCreationState) {
|
||||
final DomainResultCreationStateImpl impl = ResultsHelper.impl( domainResultCreationState );
|
||||
|
||||
ResultsHelper.impl( domainResultCreationState ).disallowPositionalSelections();
|
||||
;
|
||||
return referencedModelPart.createDomainResult(
|
||||
navigablePath,
|
||||
impl.getFromClauseAccess().resolveTableGroup(
|
||||
navigablePath,
|
||||
np -> impl.getFromClauseAccess().getTableGroup( navigablePath.getParent() )
|
||||
),
|
||||
alias,
|
||||
domainResultCreationState
|
||||
);
|
||||
}
|
||||
}
|
|
@ -115,6 +115,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
|
|||
|
||||
final DomainResultCreationStateImpl creationState = new DomainResultCreationStateImpl(
|
||||
mappingIdentifier,
|
||||
jdbcResultsMetadata,
|
||||
legacyFetchBuilders,
|
||||
sqlSelections::add,
|
||||
sessionFactory
|
||||
|
|
|
@ -6,7 +6,21 @@
|
|||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.internal.ImplicitAttributeFetchMemento;
|
||||
import org.hibernate.query.internal.ImplicitModelPartResultMemento;
|
||||
import org.hibernate.query.internal.ModelPartResultMementoBasicImpl;
|
||||
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
|
||||
import org.hibernate.query.named.FetchMemento;
|
||||
import org.hibernate.query.named.ResultMemento;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.DomainResultCreationState;
|
||||
import org.hibernate.sql.results.graph.Fetch;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -36,4 +50,37 @@ public class ResultsHelper {
|
|||
|
||||
private ResultsHelper() {
|
||||
}
|
||||
|
||||
public static boolean isIdentifier(EntityIdentifierMapping identifierDescriptor, String... names) {
|
||||
final String identifierAttributeName = identifierDescriptor instanceof SingleAttributeIdentifierMapping
|
||||
? ( (SingleAttributeIdentifierMapping) identifierDescriptor ).getAttributeName()
|
||||
: EntityIdentifierMapping.ROLE_LOCAL_NAME;
|
||||
|
||||
for ( int i = 0; i < names.length; i++ ) {
|
||||
final String name = names[ i ];
|
||||
if ( EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if ( identifierAttributeName.equals( name ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ResultMemento implicitIdentifierResult(
|
||||
EntityIdentifierMapping identifierMapping,
|
||||
EntityIdentifierNavigablePath idPath,
|
||||
ResultSetMappingResolutionContext resolutionContext) {
|
||||
return new ImplicitModelPartResultMemento( idPath, identifierMapping );
|
||||
}
|
||||
|
||||
public static FetchMemento implicitFetch(
|
||||
AttributeMapping attributeMapping,
|
||||
NavigablePath attributePath,
|
||||
ResultSetMappingResolutionContext resolutionContext) {
|
||||
return new ImplicitAttributeFetchMemento( attributePath, attributeMapping );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ public class SqlAstCreationStateImpl implements SqlAstCreationState, SqlAstProce
|
|||
private final SqlAliasBaseManager sqlAliasBaseManager;
|
||||
|
||||
private final Consumer<SqlSelection> sqlSelectionConsumer;
|
||||
private final Map<String,SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
|
||||
private final Map<String, SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.hibernate.type.spi.TypeConfiguration;
|
|||
public class SqlAstProcessingStateImpl implements SqlAstProcessingState, SqlExpressionResolver {
|
||||
private final FromClauseAccessImpl fromClauseAccess;
|
||||
|
||||
private final Map<String,SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
|
||||
private final Map<String, SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
|
||||
private final Consumer<SqlSelection> sqlSelectionConsumer;
|
||||
|
||||
private final SqlAstCreationState sqlAstCreationState;
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.util.function.BiFunction;
|
|||
|
||||
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
|
||||
import org.hibernate.query.results.ResultsHelper;
|
||||
import org.hibernate.query.results.SqlSelectionImpl;
|
||||
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.query.resultmapping;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel( annotatedClasses = SimpleEntityWithNamedMappings.class )
|
||||
@SessionFactory
|
||||
public class BaseUsageTest {
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.save( new SimpleEntityWithNamedMappings( 1, "test" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanUpData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete SimpleEntityWithNamedMappings" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
/*
|
||||
* 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.query.resultmapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class BasicResultTests extends BaseUsageTest {
|
||||
@Test
|
||||
public void testSimpleScalarMapping(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento( "name" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select name from SimpleEntityWithNamedMappings";
|
||||
final List<String> names = session.createNativeQuery( qryString, "name" ).list();
|
||||
|
||||
assertThat( names.size(), is( 1 ) );
|
||||
assertThat( names.get( 0 ), is( "test" ) );
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "name" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompoundScalarMapping(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento( "id_name" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name from SimpleEntityWithNamedMappings";
|
||||
session.createNativeQuery( qryString, "id_name" ).list();
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "id_name" );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,18 +4,13 @@
|
|||
* 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.query.named.resultmapping;
|
||||
package org.hibernate.orm.test.query.resultmapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
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 static org.hamcrest.CoreMatchers.is;
|
||||
|
@ -25,57 +20,7 @@ import static org.hamcrest.Matchers.notNullValue;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
@DomainModel( annotatedClasses = SimpleEntityWithNamedMappings.class )
|
||||
@SessionFactory
|
||||
public class UsageTests {
|
||||
// select a.{*}
|
||||
@Test
|
||||
public void testSimpleScalarMapping(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento( "id_name" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name from SimpleEntityWithNamedMappings";
|
||||
session.createNativeQuery( qryString, "id_name" ).list();
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "id_name" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleInstantiationOfScalars(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento( "id_name_dto" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name from SimpleEntityWithNamedMappings";
|
||||
final List<SimpleEntityWithNamedMappings.DropDownDto> results
|
||||
= session.createNativeQuery( qryString, "id_name_dto" ).list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
|
||||
final SimpleEntityWithNamedMappings.DropDownDto dto = results.get( 0 );
|
||||
assertThat( dto.getId(), is( 1 ) );
|
||||
assertThat( dto.getText(), is( "test" ) );
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "id_name_dto" );
|
||||
}
|
||||
);
|
||||
}
|
||||
public class EntityResultTests extends BaseUsageTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleEntityResultMapping(SessionFactoryScope scope) {
|
||||
|
@ -90,8 +35,9 @@ public class UsageTests {
|
|||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name, notes from SimpleEntityWithNamedMappings";
|
||||
final List<SimpleEntityWithNamedMappings> results
|
||||
= session.createNativeQuery( qryString, "entity" ).list();
|
||||
final List<SimpleEntityWithNamedMappings> results = session
|
||||
.createNativeQuery( qryString, "entity" )
|
||||
.list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
|
||||
final SimpleEntityWithNamedMappings entity = results.get( 0 );
|
||||
|
@ -104,20 +50,60 @@ public class UsageTests {
|
|||
);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void prepareData(SessionFactoryScope scope) {
|
||||
@Test
|
||||
public void testImplicitAttributeMapping(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.save( new SimpleEntityWithNamedMappings( 1, "test" ) );
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento(
|
||||
"entity-none" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name, notes from SimpleEntityWithNamedMappings";
|
||||
final List<SimpleEntityWithNamedMappings> results = session
|
||||
.createNativeQuery( qryString, "entity-none" )
|
||||
.list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
|
||||
final SimpleEntityWithNamedMappings entity = results.get( 0 );
|
||||
assertThat( entity.getId(), is( 1 ) );
|
||||
assertThat( entity.getName(), is( "test" ) );
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "entity-none" );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanUpData(SessionFactoryScope scope) {
|
||||
@Test
|
||||
public void testMixedAttributeMapping(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "delete SimpleEntityWithNamedMappings" ).executeUpdate();
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento(
|
||||
"entity-id-notes" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name, notes from SimpleEntityWithNamedMappings";
|
||||
final List<SimpleEntityWithNamedMappings> results = session
|
||||
.createNativeQuery( qryString, "entity-id-notes" )
|
||||
.list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
|
||||
final SimpleEntityWithNamedMappings entity = results.get( 0 );
|
||||
assertThat( entity.getId(), is( 1 ) );
|
||||
assertThat( entity.getName(), is( "test" ) );
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "entity-id-notes" );
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* 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.query.resultmapping;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.notNullValue;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class InstantiationResultTests extends BaseUsageTest {
|
||||
|
||||
@Test
|
||||
public void testSimpleInstantiationOfScalars(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
// make sure it is in the repository
|
||||
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
|
||||
.getQueryEngine()
|
||||
.getNamedQueryRepository()
|
||||
.getResultSetMappingMemento(
|
||||
"id_name_dto" );
|
||||
assertThat( mappingMemento, notNullValue() );
|
||||
|
||||
// apply it to a native-query
|
||||
final String qryString = "select id, name from SimpleEntityWithNamedMappings";
|
||||
final List<?> results = session.createNativeQuery( qryString, "id_name_dto" ).list();
|
||||
assertThat( results.size(), is( 1 ) );
|
||||
|
||||
final SimpleEntityWithNamedMappings.DropDownDto dto =
|
||||
(SimpleEntityWithNamedMappings.DropDownDto) results.get( 0 );
|
||||
|
||||
assertThat( dto.getId(), is( 1 ) );
|
||||
assertThat( dto.getText(), is( "test" ) );
|
||||
|
||||
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
|
||||
session.createStoredProcedureCall( "abc", "id_name_dto" );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,7 +4,7 @@
|
|||
* 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.query.named.resultmapping;
|
||||
package org.hibernate.orm.test.query.resultmapping;
|
||||
|
||||
import javax.persistence.Basic;
|
||||
import javax.persistence.ColumnResult;
|
||||
|
@ -51,6 +51,12 @@ import javax.persistence.SqlResultSetMapping;
|
|||
}
|
||||
)
|
||||
)
|
||||
@SqlResultSetMapping(
|
||||
name = "entity-none",
|
||||
entities = @EntityResult(
|
||||
entityClass = SimpleEntityWithNamedMappings.class
|
||||
)
|
||||
)
|
||||
@SqlResultSetMapping(
|
||||
name = "entity-id-notes",
|
||||
entities = @EntityResult(
|
|
@ -4,12 +4,13 @@
|
|||
* 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.query.named.resultmapping;
|
||||
package org.hibernate.orm.test.query.resultmapping;
|
||||
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
|
||||
import org.hibernate.query.named.NamedQueryRepository;
|
||||
import org.hibernate.query.named.NamedResultSetMappingMemento;
|
||||
import org.hibernate.query.results.ResultBuilderBasicValued;
|
||||
import org.hibernate.query.results.ResultSetMapping;
|
||||
import org.hibernate.query.results.ResultSetMappingImpl;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
|
@ -19,6 +20,7 @@ import org.hibernate.testing.orm.junit.SessionFactory;
|
|||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
|
@ -43,8 +45,15 @@ public class SimpleNamedMappingTests {
|
|||
}
|
||||
};
|
||||
|
||||
mappingMemento.resolve( mapping, querySpace -> {}, resolutionContext );
|
||||
mappingMemento.resolve( mapping, querySpace -> {
|
||||
}, resolutionContext );
|
||||
|
||||
assertThat( mapping.getNumberOfResultBuilders(), is( 1 ) );
|
||||
mapping.visitResultBuilders(
|
||||
(position, builder) -> {
|
||||
assertThat( position, is( 0 ) );
|
||||
assertThat( builder, instanceOf( ResultBuilderBasicValued.class ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue