HHH-16077 - Added named native queries cannot specify result-class
This commit is contained in:
parent
4a37bf8017
commit
e7b2f9b121
|
@ -858,7 +858,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
query.addEntity( "alias1", resultClass.getName(), LockMode.READ );
|
||||
}
|
||||
else if ( resultClass != Object.class && resultClass != Object[].class ) {
|
||||
query.addScalar( 1, resultClass );
|
||||
query.addResultTypeClass( resultClass );
|
||||
}
|
||||
return query;
|
||||
}
|
||||
|
|
|
@ -246,8 +246,13 @@ public class Builders {
|
|||
public static ResultBuilder resultClassBuilder(
|
||||
Class<?> resultMappingClass,
|
||||
ResultSetMappingResolutionContext resolutionContext) {
|
||||
final MappingMetamodelImplementor mappingMetamodel = resolutionContext
|
||||
.getSessionFactory()
|
||||
return resultClassBuilder( resultMappingClass, resolutionContext.getSessionFactory() );
|
||||
}
|
||||
|
||||
public static ResultBuilder resultClassBuilder(
|
||||
Class<?> resultMappingClass,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final MappingMetamodelImplementor mappingMetamodel = sessionFactory
|
||||
.getRuntimeMetamodels()
|
||||
.getMappingMetamodel();
|
||||
final EntityMappingType entityMappingType = mappingMetamodel.findEntityDescriptor( resultMappingClass );
|
||||
|
|
|
@ -91,6 +91,9 @@ public class ResultSetMappingImpl implements ResultSetMapping {
|
|||
}
|
||||
|
||||
public List<ResultBuilder> getResultBuilders() {
|
||||
if ( resultBuilders == null ) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return Collections.unmodifiableList( resultBuilders );
|
||||
}
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Set;
|
|||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.query.named.AbstractNamedQueryMemento;
|
||||
import org.hibernate.query.spi.QueryEngine;
|
||||
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
|
||||
|
@ -127,7 +128,7 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
|
|||
originalSqlString,
|
||||
resultSetMappingName,
|
||||
resultSetMappingClass,
|
||||
querySpaces,
|
||||
CollectionHelper.makeCopy( querySpaces ),
|
||||
getCacheable(),
|
||||
getCacheRegion(),
|
||||
getCacheMode(),
|
||||
|
|
|
@ -61,6 +61,8 @@ import org.hibernate.query.results.ResultSetMappingImpl;
|
|||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
|
||||
import org.hibernate.query.results.dynamic.DynamicResultBuilderInstantiation;
|
||||
import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderEntity;
|
||||
import org.hibernate.query.results.implicit.ImplicitResultClassBuilder;
|
||||
import org.hibernate.query.spi.AbstractQuery;
|
||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||
import org.hibernate.query.spi.MutableQueryOptions;
|
||||
|
@ -246,12 +248,6 @@ public class NativeQueryImpl<R>
|
|||
return true;
|
||||
}
|
||||
|
||||
if ( resultJavaType != null && resultJavaType != Tuple.class && !resultJavaType.isArray() ) {
|
||||
// todo : allow the expected Java type imply a builder to use
|
||||
// resultSetMapping.addResultBuilder( resultClassBuilder( resultJavaType, context ) );
|
||||
// return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
session
|
||||
|
@ -260,19 +256,21 @@ public class NativeQueryImpl<R>
|
|||
if ( resultJavaType == Tuple.class ) {
|
||||
setTupleTransformer( new NativeQueryTupleTransformer() );
|
||||
}
|
||||
else if ( resultJavaType != null && resultJavaType != Object[].class ) {
|
||||
else if ( resultJavaType != null && !resultJavaType.isArray() ) {
|
||||
switch ( resultSetMapping.getNumberOfResultBuilders() ) {
|
||||
case 0:
|
||||
case 0: {
|
||||
throw new IllegalArgumentException( "Named query exists, but did not specify a resultClass" );
|
||||
case 1:
|
||||
// would be nice to support types that are "wrappable", as in `JavaType#wrap`
|
||||
}
|
||||
case 1: {
|
||||
final Class<?> actualResultJavaType = resultSetMapping.getResultBuilders().get( 0 ).getJavaType();
|
||||
if ( actualResultJavaType != null && !resultJavaType.isAssignableFrom( actualResultJavaType ) ) {
|
||||
throw buildIncompatibleException( resultJavaType, actualResultJavaType );
|
||||
}
|
||||
break;
|
||||
default:
|
||||
}
|
||||
default: {
|
||||
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -449,7 +447,7 @@ public class NativeQueryImpl<R>
|
|||
sqlString,
|
||||
originalSqlString,
|
||||
resultSetMapping.getMappingIdentifier(),
|
||||
null,
|
||||
extractResultClass( resultSetMapping ),
|
||||
querySpaces,
|
||||
isCacheable(),
|
||||
getCacheRegion(),
|
||||
|
@ -465,6 +463,22 @@ public class NativeQueryImpl<R>
|
|||
);
|
||||
}
|
||||
|
||||
private Class<?> extractResultClass(ResultSetMappingImpl resultSetMapping) {
|
||||
final List<ResultBuilder> resultBuilders = resultSetMapping.getResultBuilders();
|
||||
if ( resultBuilders.size() == 1 ) {
|
||||
final ResultBuilder resultBuilder = resultBuilders.get( 0 );
|
||||
if ( resultBuilder instanceof ImplicitResultClassBuilder ) {
|
||||
final ImplicitResultClassBuilder resultTypeBuilder = (ImplicitResultClassBuilder) resultBuilder;
|
||||
return resultTypeBuilder.getJavaType();
|
||||
}
|
||||
else if ( resultBuilder instanceof ImplicitModelPartResultBuilderEntity ) {
|
||||
final ImplicitModelPartResultBuilderEntity resultTypeBuilder = (ImplicitModelPartResultBuilderEntity) resultBuilder;
|
||||
return resultTypeBuilder.getJavaType();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockModeType getLockMode() {
|
||||
// the JPA spec requires IllegalStateException here, even
|
||||
|
@ -841,6 +855,11 @@ public class NativeQueryImpl<R>
|
|||
: null;
|
||||
}
|
||||
|
||||
public void addResultTypeClass(Class<?> resultClass) {
|
||||
assert CollectionHelper.isEmpty( resultSetMapping.getResultBuilders() );
|
||||
registerBuilder( Builders.resultClassBuilder( resultClass, getSessionFactory() ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NativeQueryImplementor<R> addScalar(String columnAlias) {
|
||||
return registerBuilder( Builders.scalar( columnAlias ) );
|
||||
|
|
|
@ -26,6 +26,7 @@ import jakarta.persistence.NamedNativeQuery;
|
|||
import jakarta.persistence.NamedQueries;
|
||||
import jakarta.persistence.NamedQuery;
|
||||
import jakarta.persistence.Query;
|
||||
import jakarta.persistence.TypedQuery;
|
||||
|
||||
import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_LOCK_MODE;
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
|
@ -195,6 +196,19 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-11413")
|
||||
public void testNamedQueryAddedFromTypedNativeQuery() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
final Query query = entityManager.createNativeQuery( "select g.title from Game g where title = ?", String.class );
|
||||
entityManagerFactory().addNamedQuery( "the-query", query );
|
||||
|
||||
final TypedQuery<String> namedQuery = entityManager.createNamedQuery( "the-query", String.class );
|
||||
namedQuery.setParameter( 1, "abc" );
|
||||
namedQuery.getResultList();
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestForIssue(jiraKey = "HHH-14816")
|
||||
public void testQueryHintLockMode() {
|
||||
|
|
|
@ -13,7 +13,6 @@ import org.hibernate.query.Query;
|
|||
import org.hibernate.query.spi.QueryImplementor;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
|
@ -67,7 +66,6 @@ public class NativeQueryAsNamedTests {
|
|||
* Seems like this should work, but currently does not
|
||||
*/
|
||||
@Test
|
||||
@FailureExpected( reason = "Session#createNamedQuery for a native-query does not like passing the result-class" )
|
||||
public void testResultClass(SessionFactoryScope scope) {
|
||||
scope.inTransaction( (session) -> {
|
||||
final NativeQuery<String> nativeQuery = session.createNativeQuery( THE_SELECT, String.class );
|
||||
|
|
Loading…
Reference in New Issue