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 );
|
query.addEntity( "alias1", resultClass.getName(), LockMode.READ );
|
||||||
}
|
}
|
||||||
else if ( resultClass != Object.class && resultClass != Object[].class ) {
|
else if ( resultClass != Object.class && resultClass != Object[].class ) {
|
||||||
query.addScalar( 1, resultClass );
|
query.addResultTypeClass( resultClass );
|
||||||
}
|
}
|
||||||
return query;
|
return query;
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,8 +246,13 @@ public class Builders {
|
||||||
public static ResultBuilder resultClassBuilder(
|
public static ResultBuilder resultClassBuilder(
|
||||||
Class<?> resultMappingClass,
|
Class<?> resultMappingClass,
|
||||||
ResultSetMappingResolutionContext resolutionContext) {
|
ResultSetMappingResolutionContext resolutionContext) {
|
||||||
final MappingMetamodelImplementor mappingMetamodel = resolutionContext
|
return resultClassBuilder( resultMappingClass, resolutionContext.getSessionFactory() );
|
||||||
.getSessionFactory()
|
}
|
||||||
|
|
||||||
|
public static ResultBuilder resultClassBuilder(
|
||||||
|
Class<?> resultMappingClass,
|
||||||
|
SessionFactoryImplementor sessionFactory) {
|
||||||
|
final MappingMetamodelImplementor mappingMetamodel = sessionFactory
|
||||||
.getRuntimeMetamodels()
|
.getRuntimeMetamodels()
|
||||||
.getMappingMetamodel();
|
.getMappingMetamodel();
|
||||||
final EntityMappingType entityMappingType = mappingMetamodel.findEntityDescriptor( resultMappingClass );
|
final EntityMappingType entityMappingType = mappingMetamodel.findEntityDescriptor( resultMappingClass );
|
||||||
|
|
|
@ -91,6 +91,9 @@ public class ResultSetMappingImpl implements ResultSetMapping {
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<ResultBuilder> getResultBuilders() {
|
public List<ResultBuilder> getResultBuilders() {
|
||||||
|
if ( resultBuilders == null ) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
return Collections.unmodifiableList( resultBuilders );
|
return Collections.unmodifiableList( resultBuilders );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,7 @@ import java.util.Set;
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.FlushMode;
|
import org.hibernate.FlushMode;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||||
import org.hibernate.query.named.AbstractNamedQueryMemento;
|
import org.hibernate.query.named.AbstractNamedQueryMemento;
|
||||||
import org.hibernate.query.spi.QueryEngine;
|
import org.hibernate.query.spi.QueryEngine;
|
||||||
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
|
import org.hibernate.query.sql.spi.NamedNativeQueryMemento;
|
||||||
|
@ -127,7 +128,7 @@ public class NamedNativeQueryMementoImpl extends AbstractNamedQueryMemento imple
|
||||||
originalSqlString,
|
originalSqlString,
|
||||||
resultSetMappingName,
|
resultSetMappingName,
|
||||||
resultSetMappingClass,
|
resultSetMappingClass,
|
||||||
querySpaces,
|
CollectionHelper.makeCopy( querySpaces ),
|
||||||
getCacheable(),
|
getCacheable(),
|
||||||
getCacheRegion(),
|
getCacheRegion(),
|
||||||
getCacheMode(),
|
getCacheMode(),
|
||||||
|
|
|
@ -61,6 +61,8 @@ import org.hibernate.query.results.ResultSetMappingImpl;
|
||||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||||
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
|
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
|
||||||
import org.hibernate.query.results.dynamic.DynamicResultBuilderInstantiation;
|
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.AbstractQuery;
|
||||||
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
import org.hibernate.query.spi.DomainQueryExecutionContext;
|
||||||
import org.hibernate.query.spi.MutableQueryOptions;
|
import org.hibernate.query.spi.MutableQueryOptions;
|
||||||
|
@ -246,12 +248,6 @@ public class NativeQueryImpl<R>
|
||||||
return true;
|
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;
|
return false;
|
||||||
},
|
},
|
||||||
session
|
session
|
||||||
|
@ -260,19 +256,21 @@ public class NativeQueryImpl<R>
|
||||||
if ( resultJavaType == Tuple.class ) {
|
if ( resultJavaType == Tuple.class ) {
|
||||||
setTupleTransformer( new NativeQueryTupleTransformer() );
|
setTupleTransformer( new NativeQueryTupleTransformer() );
|
||||||
}
|
}
|
||||||
else if ( resultJavaType != null && resultJavaType != Object[].class ) {
|
else if ( resultJavaType != null && !resultJavaType.isArray() ) {
|
||||||
switch ( resultSetMapping.getNumberOfResultBuilders() ) {
|
switch ( resultSetMapping.getNumberOfResultBuilders() ) {
|
||||||
case 0:
|
case 0: {
|
||||||
throw new IllegalArgumentException( "Named query exists, but did not specify a resultClass" );
|
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();
|
final Class<?> actualResultJavaType = resultSetMapping.getResultBuilders().get( 0 ).getJavaType();
|
||||||
if ( actualResultJavaType != null && !resultJavaType.isAssignableFrom( actualResultJavaType ) ) {
|
if ( actualResultJavaType != null && !resultJavaType.isAssignableFrom( actualResultJavaType ) ) {
|
||||||
throw buildIncompatibleException( resultJavaType, actualResultJavaType );
|
throw buildIncompatibleException( resultJavaType, actualResultJavaType );
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
}
|
||||||
|
default: {
|
||||||
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
|
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -449,7 +447,7 @@ public class NativeQueryImpl<R>
|
||||||
sqlString,
|
sqlString,
|
||||||
originalSqlString,
|
originalSqlString,
|
||||||
resultSetMapping.getMappingIdentifier(),
|
resultSetMapping.getMappingIdentifier(),
|
||||||
null,
|
extractResultClass( resultSetMapping ),
|
||||||
querySpaces,
|
querySpaces,
|
||||||
isCacheable(),
|
isCacheable(),
|
||||||
getCacheRegion(),
|
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
|
@Override
|
||||||
public LockModeType getLockMode() {
|
public LockModeType getLockMode() {
|
||||||
// the JPA spec requires IllegalStateException here, even
|
// the JPA spec requires IllegalStateException here, even
|
||||||
|
@ -841,6 +855,11 @@ public class NativeQueryImpl<R>
|
||||||
: null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void addResultTypeClass(Class<?> resultClass) {
|
||||||
|
assert CollectionHelper.isEmpty( resultSetMapping.getResultBuilders() );
|
||||||
|
registerBuilder( Builders.resultClassBuilder( resultClass, getSessionFactory() ) );
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NativeQueryImplementor<R> addScalar(String columnAlias) {
|
public NativeQueryImplementor<R> addScalar(String columnAlias) {
|
||||||
return registerBuilder( Builders.scalar( columnAlias ) );
|
return registerBuilder( Builders.scalar( columnAlias ) );
|
||||||
|
|
|
@ -26,6 +26,7 @@ import jakarta.persistence.NamedNativeQuery;
|
||||||
import jakarta.persistence.NamedQueries;
|
import jakarta.persistence.NamedQueries;
|
||||||
import jakarta.persistence.NamedQuery;
|
import jakarta.persistence.NamedQuery;
|
||||||
import jakarta.persistence.Query;
|
import jakarta.persistence.Query;
|
||||||
|
import jakarta.persistence.TypedQuery;
|
||||||
|
|
||||||
import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_LOCK_MODE;
|
import static org.hibernate.jpa.HibernateHints.HINT_NATIVE_LOCK_MODE;
|
||||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
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
|
@Test
|
||||||
@TestForIssue(jiraKey = "HHH-14816")
|
@TestForIssue(jiraKey = "HHH-14816")
|
||||||
public void testQueryHintLockMode() {
|
public void testQueryHintLockMode() {
|
||||||
|
|
|
@ -13,7 +13,6 @@ import org.hibernate.query.Query;
|
||||||
import org.hibernate.query.spi.QueryImplementor;
|
import org.hibernate.query.spi.QueryImplementor;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
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.JiraKey;
|
||||||
import org.hibernate.testing.orm.junit.RequiresDialect;
|
import org.hibernate.testing.orm.junit.RequiresDialect;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
@ -67,7 +66,6 @@ public class NativeQueryAsNamedTests {
|
||||||
* Seems like this should work, but currently does not
|
* Seems like this should work, but currently does not
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
@FailureExpected( reason = "Session#createNamedQuery for a native-query does not like passing the result-class" )
|
|
||||||
public void testResultClass(SessionFactoryScope scope) {
|
public void testResultClass(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( (session) -> {
|
scope.inTransaction( (session) -> {
|
||||||
final NativeQuery<String> nativeQuery = session.createNativeQuery( THE_SELECT, String.class );
|
final NativeQuery<String> nativeQuery = session.createNativeQuery( THE_SELECT, String.class );
|
||||||
|
|
Loading…
Reference in New Issue