ResultSet mapping

- Support for implicit and mixed attribute mappings for `@EntityResult`
This commit is contained in:
Steve Ebersole 2020-08-12 16:17:51 -05:00
parent b744d7891c
commit b7eed1842c
18 changed files with 563 additions and 92 deletions

View File

@ -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,

View File

@ -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

View File

@ -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;
}
}

View File

@ -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
);
}
}

View File

@ -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;
}

View File

@ -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
);
}
}

View File

@ -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
);
}
}

View File

@ -115,6 +115,7 @@ public class ResultSetMappingImpl implements ResultSetMapping {
final DomainResultCreationStateImpl creationState = new DomainResultCreationStateImpl(
mappingIdentifier,
jdbcResultsMetadata,
legacyFetchBuilders,
sqlSelections::add,
sessionFactory

View File

@ -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 );
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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();
}
);
}
}

View File

@ -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" );
}
);
}
}

View File

@ -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" );
}
);
}

View File

@ -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" );
}
);
}
}

View File

@ -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(

View File

@ -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 ) );
}
);
}
}