HHH-17764 query result types and single-item selection lists

- allow single-item auto-instantiation
- check the type of the selection item against the given result type
This commit is contained in:
Gavin King 2024-02-20 22:17:38 +01:00
parent bb477c180a
commit c45f047443
19 changed files with 367 additions and 112 deletions

View File

@ -29,7 +29,6 @@ import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.TypeMismatchException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.GraphSemantic;
import org.hibernate.internal.EntityManagerMessageLogger;
@ -654,9 +653,6 @@ public abstract class AbstractQuery<R>
catch (IllegalQueryOperationException e) {
throw new IllegalStateException( e );
}
catch (TypeMismatchException e) {
throw new IllegalArgumentException( e );
}
catch (HibernateException e) {
throw getSession().getExceptionConverter().convert( e );
}

View File

@ -39,7 +39,6 @@ import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.NonUniqueResultException;
import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException;
import org.hibernate.UnknownProfileException;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
@ -89,6 +88,8 @@ import static org.hibernate.jpa.QueryHints.HINT_CACHE_REGION;
import static org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE;
import static org.hibernate.jpa.QueryHints.HINT_FOLLOW_ON_LOCKING;
import static org.hibernate.jpa.QueryHints.HINT_READONLY;
import static org.hibernate.query.sqm.internal.SqmUtil.isHqlTuple;
import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType;
/**
* @author Steve Ebersole
@ -108,24 +109,24 @@ public abstract class AbstractSelectionQuery<R>
}
protected TupleMetadata buildTupleMetadata(SqmStatement<?> statement, Class<R> resultType) {
if ( isInstantiableWithoutMetadata( resultType ) ) {
// no need to build metadata for instantiating tuples
return null;
}
else {
if ( statement instanceof SqmSelectStatement<?> ) {
final SqmSelectStatement<?> select = (SqmSelectStatement<?>) statement;
final List<SqmSelection<?>> selections =
select.getQueryPart().getFirstQuerySpec().getSelectClause()
.getSelections();
if ( Tuple.class.equals( resultType ) || selections.size() > 1 ) {
return getTupleMetadata( selections );
}
else {
// only one element in select list,
// we don't support instantiation
return null;
}
return isTupleMetadataRequired( resultType, selections.get(0) )
? getTupleMetadata( selections )
: null;
}
else {
return null;
}
}
private static <R> boolean isTupleMetadataRequired(Class<R> resultType, SqmSelection<?> selection) {
return isHqlTuple( selection )
|| !isInstantiableWithoutMetadata( resultType )
&& !isSelectionAssignableToResultType( selection, resultType );
}
private TupleMetadata getTupleMetadata(List<SqmSelection<?>> selections) {
@ -431,9 +432,6 @@ public abstract class AbstractSelectionQuery<R>
catch (IllegalQueryOperationException e) {
throw new IllegalStateException( e );
}
catch (TypeMismatchException e) {
throw new IllegalArgumentException( e );
}
catch (HibernateException he) {
throw getSession().getExceptionConverter().convert( he, getQueryOptions().getLockOptions() );
}

View File

@ -12,7 +12,6 @@ import java.util.List;
import java.util.Map;
import jakarta.persistence.Tuple;
import org.hibernate.AssertionFailure;
import org.hibernate.InstantiationException;
import org.hibernate.ScrollMode;
import org.hibernate.engine.spi.EntityHolder;
@ -20,7 +19,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.SubselectFetch;
import org.hibernate.internal.EmptyScrollableResults;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.query.Query;
import org.hibernate.query.TupleTransformer;
@ -43,6 +41,7 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
import org.hibernate.sql.results.internal.RowTransformerArrayImpl;
import org.hibernate.sql.results.internal.RowTransformerCheckingImpl;
import org.hibernate.sql.results.internal.RowTransformerConstructorImpl;
import org.hibernate.sql.results.internal.RowTransformerJpaTupleImpl;
import org.hibernate.sql.results.internal.RowTransformerListImpl;
@ -56,7 +55,9 @@ import org.hibernate.sql.results.spi.ResultsConsumer;
import org.hibernate.sql.results.spi.RowTransformer;
import static org.hibernate.internal.util.ReflectHelper.isClass;
import static org.hibernate.internal.util.collections.ArrayHelper.toStringArray;
import static org.hibernate.query.sqm.internal.QuerySqmImpl.CRITERIA_HQL_STRING;
import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType;
/**
* Standard Hibernate implementation of SelectQueryPlan for SQM-backed
@ -203,59 +204,59 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
return selections.size() == 1 ? selections.get( 0 ) : null;
}
private static Class<?> selectionType(SqmSelection<?> selection) {
return selection != null && !selection.getSelectableNode().isCompoundSelection() ?
selection.getNodeJavaType().getJavaTypeClass()
: null;
}
private static final Map<Class<?>,Class<?>> WRAPPERS
= Map.of(
boolean.class, Boolean.class,
int.class, Integer.class,
long.class, Long.class,
short.class, Short.class,
byte.class, Byte.class,
float.class, Float.class,
double.class, Double.class,
char.class, Character.class
);
@SuppressWarnings("unchecked")
protected static <T> RowTransformer<T> determineRowTransformer(
SqmSelectStatement<?> sqm,
Class<T> resultType,
Class<T> resultClass,
TupleMetadata tupleMetadata,
QueryOptions queryOptions) {
if ( queryOptions.getTupleTransformer() != null ) {
return makeRowTransformerTupleTransformerAdapter( sqm, queryOptions );
}
else if ( resultType == null ) {
else if ( resultClass == null ) {
return RowTransformerStandardImpl.instance();
}
else {
final Class<T> resultType = (Class<T>)
WRAPPERS.getOrDefault( resultClass, resultClass );
final SqmSelection<?> selection = singleSelection( sqm );
if ( resultType.isArray() && resultType != selectionType( selection ) ) {
if ( isSelectionAssignableToResultType( selection, resultType ) ) {
return RowTransformerSingularReturnImpl.instance();
}
else if ( resultType.isArray() ) {
return (RowTransformer<T>) RowTransformerArrayImpl.instance();
}
else if ( resultType == List.class && resultType != selectionType( selection ) ) {
else if ( List.class.equals( resultType ) ) {
return (RowTransformer<T>) RowTransformerListImpl.instance();
}
else if ( Tuple.class.equals( resultType ) ) {
return (RowTransformer<T>) new RowTransformerJpaTupleImpl( tupleMetadata );
}
else if ( Map.class.equals( resultType ) ) {
return (RowTransformer<T>) new RowTransformerMapImpl( tupleMetadata );
}
else if ( isClass( resultType ) ) {
try {
return new RowTransformerConstructorImpl<>( resultType, tupleMetadata );
}
catch (InstantiationException ie) {
return new RowTransformerCheckingImpl<>( resultType );
}
}
else {
// NOTE : if we get here :
// 1) there is no TupleTransformer specified
// 2) an explicit result-type, other than an array or List, was specified
if ( tupleMetadata == null ) {
if ( selection != null ) {
return RowTransformerSingularReturnImpl.instance();
}
else {
throw new AssertionFailure( "Query defined multiple selections, should have had TupleMetadata" );
}
}
else {
if ( Tuple.class.equals( resultType ) ) {
return (RowTransformer<T>) new RowTransformerJpaTupleImpl( tupleMetadata );
}
else if ( Map.class.equals( resultType ) ) {
return (RowTransformer<T>) new RowTransformerMapImpl( tupleMetadata );
}
else if ( isClass( resultType ) ) {
return new RowTransformerConstructorImpl<>( resultType, tupleMetadata );
}
else {
throw new InstantiationException( "Query result type is not instantiable", resultType );
}
}
return new RowTransformerCheckingImpl<>( resultType );
}
}
}
@ -279,10 +280,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
@SuppressWarnings("unchecked")
TupleTransformer<T> tupleTransformer = (TupleTransformer<T>) queryOptions.getTupleTransformer();
return new RowTransformerTupleTransformerAdapter<T>(
ArrayHelper.toStringArray( aliases ),
tupleTransformer
);
return new RowTransformerTupleTransformerAdapter<>( toStringArray( aliases ), tupleTransformer );
}
@Override
@ -424,10 +422,7 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
final SqlAstTranslator<JdbcOperationQuerySelect> selectTranslator =
sessionFactory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory()
.buildSelectTranslator(
sessionFactory,
sqmInterpretation.getSqlAst()
);
.buildSelectTranslator( sessionFactory, sqmInterpretation.getSqlAst() );
final Map<QueryParameterImplementor<?>, Map<SqmParameter<?>, List<JdbcParametersList>>> jdbcParamsXref
= SqmUtil.generateJdbcParamsXref( domainParameterXref, sqmInterpretation::getJdbcParamsBySqmParam );

View File

@ -26,7 +26,6 @@ import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.engine.query.spi.EntityGraphQueryHint;
import org.hibernate.engine.spi.LoadQueryInfluencers;
@ -692,9 +691,6 @@ public class QuerySqmImpl<R>
catch (IllegalQueryOperationException e) {
throw new IllegalStateException( e );
}
catch (TypeMismatchException e) {
throw new IllegalArgumentException( e );
}
catch (HibernateException e) {
throw getSession().getExceptionConverter().convert( e );
}

View File

@ -67,7 +67,6 @@ import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.sql.results.internal.TupleMetadata;
import org.hibernate.sql.results.spi.ResultsConsumer;
import org.hibernate.sql.results.spi.SingleResultConsumer;
import org.hibernate.type.descriptor.java.JavaType;
import static java.util.stream.Collectors.toList;
import static org.hibernate.jpa.HibernateHints.HINT_CACHEABLE;
@ -82,6 +81,7 @@ import static org.hibernate.jpa.SpecHints.HINT_SPEC_CACHE_RETRIEVE_MODE;
import static org.hibernate.jpa.SpecHints.HINT_SPEC_CACHE_STORE_MODE;
import static org.hibernate.query.spi.SqlOmittingQueryOptions.omitSqlQueryOptions;
import static org.hibernate.query.sqm.internal.SqmInterpretationsKey.createInterpretationsKey;
import static org.hibernate.query.sqm.internal.SqmUtil.isSelectionAssignableToResultType;
import static org.hibernate.query.sqm.internal.SqmUtil.sortSpecification;
/**
@ -131,17 +131,14 @@ public class SqmSelectionQueryImpl<R> extends AbstractSelectionQuery<R>
}
else {
final SqmSelection<?> selection = selections.get(0);
if ( selection!=null ) {
final JavaType<?> javaType = selection.getNodeJavaType();
if ( javaType != null) {
return javaType.getJavaTypeClass();
}
if ( isSelectionAssignableToResultType( selection, expectedResultType ) ) {
return selection.getNodeJavaType().getJavaTypeClass();
}
else {
// let's assume there's some
// way to instantiate it
return expectedResultType;
}
// due to some error in the query,
// we don't have any information,
// so just let it through so the
// user sees the real error
return expectedResultType;
}
}
else if ( expectedResultType != null ) {

View File

@ -52,12 +52,14 @@ import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmAliasedNodeRef;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.query.sqm.tree.from.SqmJoin;
import org.hibernate.query.sqm.tree.from.SqmQualifiedJoin;
import org.hibernate.query.sqm.tree.from.SqmRoot;
import org.hibernate.query.sqm.tree.select.SqmSelectStatement;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.query.sqm.tree.select.SqmSelection;
import org.hibernate.query.sqm.tree.select.SqmSortSpecification;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.SqlTreeCreationException;
@ -69,6 +71,7 @@ import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcParametersList;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.internal.BasicTypeImpl;
import org.hibernate.type.internal.ConvertedBasicTypeImpl;
import org.hibernate.type.spi.TypeConfiguration;
@ -601,6 +604,26 @@ public class SqmUtil {
}
}
public static boolean isSelectionAssignableToResultType(SqmSelection<?> selection, Class<?> expectedResultType) {
if ( expectedResultType == null
|| selection != null && selection.getSelectableNode() instanceof SqmParameter ) {
return true;
}
else if ( selection == null
|| !isHqlTuple( selection ) && selection.getSelectableNode().isCompoundSelection() ) {
return false;
}
else {
final JavaType<?> nodeJavaType = selection.getNodeJavaType();
return nodeJavaType != null
&& expectedResultType.isAssignableFrom( nodeJavaType.getJavaTypeClass() );
}
}
public static boolean isHqlTuple(SqmSelection<?> selection) {
return selection != null && selection.getSelectableNode() instanceof SqmTuple;
}
private static class CriteriaParameterCollector {
private Set<SqmParameter<?>> sqmParameters;
private Map<JpaCriteriaParameter<?>, List<SqmJpaCriteriaParameterWrapper<?>>> jpaCriteriaParamResolutions;

View File

@ -0,0 +1,41 @@
/*
* 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.sql.results.internal;
import org.hibernate.TypeMismatchException;
import org.hibernate.sql.results.spi.RowTransformer;
/**
* @author Gavin King
*/
public class RowTransformerCheckingImpl<R> implements RowTransformer<R> {
private final Class<R> type;
public RowTransformerCheckingImpl(Class<R> type) {
this.type = type;
}
@Override
@SuppressWarnings("unchecked")
public R transformRow(Object[] row) {
final Object result = row[0];
if ( result == null || type.isInstance( result ) ) {
return (R) result;
}
else {
throw new TypeMismatchException( "Result type is '" + type.getSimpleName()
+ "' but the query returned a '" + result.getClass().getSimpleName() + "'" );
}
}
@Override
public int determineNumberOfResultElements(int rawElementCount) {
return 1;
}
}

View File

@ -123,13 +123,13 @@ public class AnyImplicitDiscriminatorTest {
public void testHqlAnyIdQuery(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<PropertySet> list1 = session.createQuery(
List<ImplicitPropertyHolder> list1 = session.createQuery(
"select p from ImplicitPropertyHolder p where id(p.property) = 666",
PropertySet.class ).list();
ImplicitPropertyHolder.class ).list();
assertEquals( 0, list1.size() );
List<PropertySet> list2 = session.createQuery(
List<ImplicitPropertyHolder> list2 = session.createQuery(
"select p from ImplicitPropertyHolder p where type(p.property) = IntegerProperty",
PropertySet.class ).list();
ImplicitPropertyHolder.class ).list();
assertEquals( 1, list2.size() );
}

View File

@ -136,13 +136,13 @@ public class AnyTest {
public void testHqlAnyIdQuery(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
List<PropertySet> list1 = session.createQuery(
List<PropertyHolder> list1 = session.createQuery(
"select p from PropertyHolder p where id(p.property) = 666",
PropertySet.class ).list();
PropertyHolder.class ).list();
assertEquals( 0, list1.size() );
List<PropertySet> list2 = session.createQuery(
List<PropertyHolder> list2 = session.createQuery(
"select p from PropertyHolder p where type(p.property) = IntegerProperty",
PropertySet.class ).list();
PropertyHolder.class ).list();
assertEquals( 1, list2.size() );
}

View File

@ -2,6 +2,7 @@ package org.hibernate.orm.test.any.annotations;
import java.util.List;
import jakarta.persistence.TypedQuery;
import org.hibernate.Hibernate;
import org.hibernate.annotations.Any;
import org.hibernate.annotations.AnyDiscriminator;
@ -82,9 +83,9 @@ public class EagerAnyDiscriminatorQueryTest {
public void testHQLQuery(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
Query q = entityManager.createQuery(
TypedQuery<PropertyHolder> q = entityManager.createQuery(
"select p from PropertyHolder p",
LazyAnyDiscriminatorQueryTest.PropertyHolder.class
PropertyHolder.class
);
List<PropertyHolder> results = q.getResultList();
assertThat( results.size() ).isEqualTo( 1 );

View File

@ -88,14 +88,14 @@ public class JoinedInheritanceDiscriminatorSelectionTest {
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select p.class from ParentEntity p",
String.class
Class.class
).getResultList() ).hasSize( 4 );
inspector.assertNumberOfJoins( 0, 0 );
inspector.clear();
assertThat( session.createQuery(
"select type(p) from ParentEntity p",
String.class
Class.class
).getResultList() ).hasSize( 4 );
inspector.assertNumberOfJoins( 0, 0 );
} );

View File

@ -13,6 +13,7 @@ import java.util.Map;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.Test;

View File

@ -61,22 +61,22 @@ public class ConvertedAttributesTypecheckTest {
@Test
public void testUnaryExpressionOnConvertedNumber(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final String result = session.createQuery(
"select -convertedNumber from TestEntity",
String.class
session.createQuery(
"from TestEntity where -convertedNumber = -123",
TestEntity.class
).getSingleResult();
assertThat( result ).isEqualTo( "-123" );
} );
}
@Test
public void testFromDurationExpressionOnConvertedDuration(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final String result = session.createQuery(
"select convertedDuration by day from TestEntity",
String.class
).getSingleResult();
assertThat( Long.parseLong( result ) ).isEqualTo( Duration.ofDays( 3 ).toMillis() );
session.createQuery(
"from TestEntity where convertedDuration by day = ?1",
TestEntity.class
)
.setParameter( 1, Duration.ofDays( 3 ).toNanos() )
.getSingleResult();
} );
}

View File

@ -118,9 +118,9 @@ public class ProxyAsQueryParameterTest {
.setParameter( "productId", LUXURY_PRODUCT_ID )
.getSingleResult();
assertThat( Hibernate.isInitialized( product.getVendor() ) ).isFalse();
final LuxuryCarVendor result = session.createQuery(
final CarVendor result = session.createQuery(
"from CarVendor v where v = :vendor",
LuxuryCarVendor.class
CarVendor.class
).setParameter( "vendor", product.getVendor() ).getSingleResult();
assertThat( result.getId() ).isEqualTo( product.getVendor().getId() );
} );

View File

@ -2002,7 +2002,7 @@ public class FunctionTests {
session -> {
session.createQuery("select format(e.theDate as 'dd/MM/yy'), format(e.theDate as 'EEEE, MMMM dd, yyyy') from EntityOfBasics e", Object[].class)
.list();
session.createQuery("select format(e.theTimestamp as 'dd/MM/yyyy ''at'' HH:mm:ss') from EntityOfBasics e", Date.class)
session.createQuery("select format(e.theTimestamp as 'dd/MM/yyyy ''at'' HH:mm:ss') from EntityOfBasics e", String.class)
.list();
assertThat(
@ -2019,7 +2019,7 @@ public class FunctionTests {
public void testFormatTime(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createQuery("select format(e.theTime as 'hh:mm:ss a') from EntityOfBasics e", Date.class)
session.createQuery("select format(e.theTime as 'hh:mm:ss a') from EntityOfBasics e", String.class)
.list();
assertThat(
session.createQuery("select format(theTime as '''Hello'', hh:mm:ss a') from EntityOfBasics where id=123", String.class).getResultList().get(0),

View File

@ -0,0 +1,208 @@
package org.hibernate.orm.test.query.hql;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import jakarta.persistence.Tuple;
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.Test;
import java.util.List;
import java.util.Map;
import static org.junit.jupiter.api.Assertions.assertEquals;
@DomainModel(
annotatedClasses = {
ImplicitInstantiationTest2.Thing.class
}
)
@SessionFactory
public class ImplicitInstantiationTest2 {
static class Record {
String name;
public Record(String name) {
this.name = name;
}
String name() {
return name;
}
}
@Test
public void testRecordInstantiationWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Record result = session.createSelectionQuery("select upper(name) from Thing", Record.class).getSingleResult();
assertEquals( result.name(), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testSqlRecordInstantiationWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Record result = session.createNativeQuery("select upper(name) as name from thingy_table", Record.class)
.addSynchronizedEntityClass(Thing.class)
.getSingleResult();
assertEquals( result.name(), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testTupleInstantiationWithAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Tuple result = session.createQuery("select upper(name) as name from Thing", Tuple.class).getSingleResult();
assertEquals( result.get("name"), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testTupleInstantiationWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Tuple result = session.createSelectionQuery("select upper(name) from Thing", Tuple.class).getSingleResult();
assertEquals( result.get(0), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testMapInstantiationWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Map result = session.createSelectionQuery("select upper(name) from Thing", Map.class).getSingleResult();
assertEquals( result.get("0"), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testMapInstantiationWithAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Map result = session.createQuery("select upper(name) as name from Thing", Map.class).getSingleResult();
assertEquals( result.get("name"), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testListInstantiationWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
List result = session.createSelectionQuery("select upper(name) from Thing", List.class).getSingleResult();
assertEquals( result.get(0), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testListInstantiationWithAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
List result = session.createQuery("select upper(name) as name from Thing", List.class).getSingleResult();
assertEquals( result.get(0), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testSqlTupleInstantiationWithAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Tuple result = session.createNativeQuery("select upper(name) as name from thingy_table", Tuple.class)
.addSynchronizedEntityClass(Thing.class)
.getSingleResult();
assertEquals( result.get("name"), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testSqlMapInstantiationWithAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
Map result = session.createNativeQuery("select upper(name) as name from thingy_table", Map.class)
.addSynchronizedEntityClass(Thing.class)
.getSingleResult();
assertEquals( result.get("name"), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Test
public void testSqlListInstantiationWithoutAlias(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.persist(new Thing(1L, "thing"));
List result = session.createNativeQuery("select upper(name) as name from thingy_table", List.class)
.addSynchronizedEntityClass(Thing.class)
.getSingleResult();
assertEquals( result.get(0), "THING" );
session.getTransaction().setRollbackOnly();
}
);
}
@Entity(name = "Thing")
@Table(name = "thingy_table")
public class Thing {
private Long id;
private String name;
public Thing(Long id, String name) {
this.id = id;
this.name = name;
}
Thing() {
}
@Id
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
}

View File

@ -93,9 +93,9 @@ public class MultiValuedParameterTest extends BaseSessionFactoryFunctionalTest {
public void test() {
inTransaction( session -> {
final List<BigInteger> ids = List.of( BigInteger.ZERO, BigInteger.ONE, BigInteger.TWO );
final List<EntityWithNumericId> resultList = session.createQuery(
final List<BigInteger> resultList = session.createQuery(
"select id from EntityWithNumericId e WHERE e.id in (:ids)",
EntityWithNumericId.class
BigInteger.class
).setParameter( "ids", ids ).getResultList();
assertThat( resultList.size(), is( 3 ) );
assertThat( resultList, is( ids ) );

View File

@ -64,9 +64,9 @@ public class HqlTreatJoinFetchTest {
public void testJoinFetchRootTreat(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
QueryImplementor<TestEntity> query = session.createQuery(
QueryImplementor<BaseEntity> query = session.createQuery(
"select t from BaseEntity t join fetch treat(t as JoinedEntity).testEntity j left join fetch j.joined2 e",
TestEntity.class
BaseEntity.class
);
query.list();
}

View File

@ -78,8 +78,7 @@ public class EagerManyToOneTest {
);
scope.inTransaction(
entityManager -> {
List<EagerManyToOne2Test.Child> children = entityManager.createQuery( "select c from Child c", EagerManyToOne2Test.Child.class )
List<Child> children = entityManager.createQuery( "select c from Child c", Child.class )
.getResultList();
assertThat( children.size() ).isEqualTo( 0 );
}