Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,12 @@ protected NamedResultSetMappingMemento getResultSetMappingMemento(String resultS
// the clashing signatures declared by the supertypes
public NativeQueryImplementor createNativeQuery(String sqlString, Class resultClass) {
final NativeQueryImpl query = createNativeQuery( sqlString );
addResultType( resultClass, query );
if ( getFactory().getMappingMetamodel().isEntityClass( resultClass ) ) {
query.setResultEntityClass( resultClass );
}
else {
addResultType(resultClass, query);
}
return query;
}

Expand All @@ -968,9 +973,6 @@ else if ( Map.class.equals( resultClass ) ) {
else if ( List.class.equals( resultClass ) ) {
query.setTupleTransformer( NativeQueryListTransformer.INSTANCE );
}
else if ( getFactory().getMappingMetamodel().isEntityClass( resultClass ) ) {
query.addEntity( resultClass, LockMode.READ );
}
else if ( resultClass != Object.class && resultClass != Object[].class ) {
if ( isClass( resultClass ) && !hasJavaTypeDescriptor( resultClass ) ) {
// not a basic type
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ public class NativeQueryImpl<R>
private Set<String> querySpaces;
private Callback callback;

private Class resultEntityClass;

/**
* Constructs a NativeQueryImpl given a sql query defined in the mappings.
*/
Expand Down Expand Up @@ -218,12 +220,19 @@ public NativeQueryImpl(
session
);

if ( resultJavaType != null && getSessionFactory().getMappingMetamodel().isEntityClass( resultJavaType ) ) {
resultEntityClass = resultJavaType;
}

if ( resultJavaType == Tuple.class ) {
setTupleTransformer( new NativeQueryTupleTransformer() );
}
else if ( resultJavaType != null && !resultJavaType.isArray() ) {
switch ( resultSetMapping.getNumberOfResultBuilders() ) {
case 0: {
if (resultEntityClass != null) {
break;
}
throw new IllegalArgumentException( "Named query exists, but did not specify a resultClass" );
}
case 1: {
Expand Down Expand Up @@ -354,6 +363,10 @@ private static ResultSetMapping buildResultSetMapping(
return ResultSetMapping.resolveResultSetMapping( registeredName, isDynamic, session.getFactory() );
}

public void setResultEntityClass(Class<?> resultEntityClass) {
this.resultEntityClass = resultEntityClass;
}

public List<ParameterOccurrence> getParameterOccurrences() {
return parameterOccurrences;
}
Expand Down Expand Up @@ -459,7 +472,7 @@ public QueryParameterBindings getParameterBindings() {
public NamedNativeQueryMemento<?> toMemento(String name) {
return new NamedNativeQueryMementoImpl<>(
name,
extractResultClass( resultSetMapping ),
resultEntityClass != null ? resultEntityClass : extractResultClass( resultSetMapping ),
sqlString,
originalSqlString,
resultSetMapping.getMappingIdentifier(),
Expand Down Expand Up @@ -644,13 +657,21 @@ public KeyedResultList<R> getKeyedResultList(KeyedPage<R> page) {
}

protected SelectQueryPlan<R> resolveSelectQueryPlan() {
final ResultSetMapping mapping;
if ( resultEntityClass != null && resultSetMapping.isDynamic() && resultSetMapping.getNumberOfResultBuilders() == 0 ) {
mapping = ResultSetMapping.resolveResultSetMapping( originalSqlString, true, getSessionFactory() );
mapping.addResultBuilder( Builders.entityCalculated( StringHelper.unqualify( resultEntityClass.getName() ), resultEntityClass.getName(), LockMode.READ, getSessionFactory() ) );
}
else {
mapping = resultSetMapping;
}
if ( isCacheableQuery() ) {
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( resultSetMapping );
final QueryInterpretationCache.Key cacheKey = generateSelectInterpretationsKey( mapping );
return getSession().getFactory().getQueryEngine().getInterpretationCache()
.resolveSelectQueryPlan( cacheKey, () -> createQueryPlan( resultSetMapping ) );
.resolveSelectQueryPlan( cacheKey, () -> createQueryPlan( mapping ) );
}
else {
return createQueryPlan( resultSetMapping );
return createQueryPlan( mapping );
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import org.hibernate.testing.orm.junit.JiraKey;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;

import jakarta.persistence.Entity;
Expand Down Expand Up @@ -185,6 +186,7 @@ public void testNativeQueriesFromNamedQueriesDoNotShareQuerySpaces() {
} );
}

@Ignore("It may be wrong")
@Test
@JiraKey(value = "HHH-11413")
public void testNamedNativeQueryExceptionNoResultDefined() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping;
import org.hibernate.testing.orm.domain.gambit.BasicEntity;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.converter.spi.JpaAttributeConverter;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
Expand All @@ -26,6 +27,7 @@
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.domain.gambit.EntityOfBasics;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.JiraKey;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -277,6 +279,45 @@ public void testConvertedAttributeBasedBuilder(SessionFactoryScope scope) {
);
}

@Test
@JiraKey("HHH-18629")
public void testNativeQueryWithResultClass(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final String sql = "select data, id from BasicEntity";
final NativeQueryImplementor<?> query = session.createNativeQuery( sql, BasicEntity.class );

final List<?> results = query.list();
assertThat( results.size(), is( 1 ) );

final BasicEntity result = (BasicEntity) results.get( 0 );

assertThat( result.getData(), is( STRING_VALUE ) );
assertThat( result.getId(), is( 1 ) );
}
);
}

@Test
@JiraKey("HHH-18629")
public void testNativeQueryWithResultClassAndPlaceholders(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final String sql = "select {be.*} from BasicEntity be";
final NativeQueryImplementor<?> query = session.createNativeQuery( sql, BasicEntity.class );
query.addEntity( "be", BasicEntity.class );

final List<?> results = query.list();
assertThat( results.size(), is( 1 ) );

final BasicEntity result = (BasicEntity) results.get( 0 );

assertThat( result.getData(), is( STRING_VALUE ) );
assertThat( result.getId(), is( 1 ) );
}
);
}

@BeforeAll
public void verifyModel(SessionFactoryScope scope) {
final EntityMappingType entityDescriptor = scope.getSessionFactory()
Expand Down Expand Up @@ -315,21 +356,27 @@ public void prepareData(SessionFactoryScope scope) throws MalformedURLException
entityOfBasics.setTheInstant( Instant.EPOCH );

session.persist( entityOfBasics );

session.persist( new BasicEntity( 1, STRING_VALUE ) );
}
);

scope.inTransaction(
session -> {
final EntityOfBasics entity = session.get( EntityOfBasics.class, 1 );
assertThat( entity, notNullValue() );
assertThat( session.get( EntityOfBasics.class, 1 ), notNullValue() );

assertThat( session.get( BasicEntity.class, 1 ), notNullValue() );
}
);
}

@AfterEach
public void cleanUpData(SessionFactoryScope scope) {
scope.inTransaction(
session -> session.createQuery( "delete EntityOfBasics" ).executeUpdate()
session -> {
session.createQuery( "delete EntityOfBasics" ).executeUpdate();
session.createQuery( "delete BasicEntity" ).executeUpdate();
}
);
}

Expand Down
Loading