HHH-17598 Allow array typed queries without result wrapping
This commit is contained in:
parent
2f60e08c64
commit
f8d84f9f7f
|
@ -195,18 +195,18 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
return new MySqmJdbcExecutionContextAdapter( executionContext, jdbcSelect, subSelectFetchKeyHandler, hql );
|
return new MySqmJdbcExecutionContextAdapter( executionContext, jdbcSelect, subSelectFetchKeyHandler, hql );
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Class<?> singleSelectionType(SqmSelectStatement<?> sqm) {
|
private static SqmSelection<?> singleSelection(SqmSelectStatement<?> sqm) {
|
||||||
final List<SqmSelection<?>> selections = sqm.getQueryPart()
|
final List<SqmSelection<?>> selections = sqm.getQueryPart()
|
||||||
.getFirstQuerySpec()
|
.getFirstQuerySpec()
|
||||||
.getSelectClause()
|
.getSelectClause()
|
||||||
.getSelections();
|
.getSelections();
|
||||||
if ( selections.size() == 1 ) {
|
return selections.size() == 1 ? selections.get( 0 ) : null;
|
||||||
final SqmSelection<?> sqmSelection = selections.get( 0 );
|
}
|
||||||
return sqmSelection.getSelectableNode().isCompoundSelection() ?
|
|
||||||
null :
|
private static Class<?> selectionType(SqmSelection<?> selection) {
|
||||||
sqmSelection.getNodeJavaType().getJavaTypeClass();
|
return selection != null && !selection.getSelectableNode().isCompoundSelection() ?
|
||||||
}
|
selection.getNodeJavaType().getJavaTypeClass()
|
||||||
return null;
|
: null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
|
@ -221,37 +221,40 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
||||||
else if ( resultType == null ) {
|
else if ( resultType == null ) {
|
||||||
return RowTransformerStandardImpl.instance();
|
return RowTransformerStandardImpl.instance();
|
||||||
}
|
}
|
||||||
else if ( resultType == Object[].class ) {
|
|
||||||
return (RowTransformer<T>) RowTransformerArrayImpl.instance();
|
|
||||||
}
|
|
||||||
else if ( resultType == List.class && resultType != singleSelectionType( sqm ) ) {
|
|
||||||
return (RowTransformer<T>) RowTransformerListImpl.instance();
|
|
||||||
}
|
|
||||||
else {
|
else {
|
||||||
// NOTE : if we get here :
|
final SqmSelection<?> selection = singleSelection( sqm );
|
||||||
// 1) there is no TupleTransformer specified
|
if ( resultType.isArray() && resultType != selectionType( selection ) ) {
|
||||||
// 2) an explicit result-type, other than an array or List, was specified
|
return (RowTransformer<T>) RowTransformerArrayImpl.instance();
|
||||||
|
}
|
||||||
if ( tupleMetadata == null ) {
|
else if ( resultType == List.class && resultType != selectionType( selection ) ) {
|
||||||
if ( sqm.getQueryPart().getFirstQuerySpec().getSelectClause().getSelections().size() == 1 ) {
|
return (RowTransformer<T>) RowTransformerListImpl.instance();
|
||||||
return RowTransformerSingularReturnImpl.instance();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new AssertionFailure( "Query defined multiple selections, should have had TupleMetadata" );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( Tuple.class.equals( resultType ) ) {
|
// NOTE : if we get here :
|
||||||
return (RowTransformer<T>) new RowTransformerJpaTupleImpl( tupleMetadata );
|
// 1) there is no TupleTransformer specified
|
||||||
}
|
// 2) an explicit result-type, other than an array or List, was specified
|
||||||
else if ( Map.class.equals( resultType ) ) {
|
|
||||||
return (RowTransformer<T>) new RowTransformerMapImpl( tupleMetadata );
|
if ( tupleMetadata == null ) {
|
||||||
}
|
if ( selection != null ) {
|
||||||
else if ( isClass( resultType ) ) {
|
return RowTransformerSingularReturnImpl.instance();
|
||||||
return new RowTransformerConstructorImpl<>( resultType, tupleMetadata );
|
}
|
||||||
|
else {
|
||||||
|
throw new AssertionFailure( "Query defined multiple selections, should have had TupleMetadata" );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new InstantiationException( "Query result type is not instantiable", resultType );
|
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 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public class ConvertedListAttributeQueryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings( "rawtypes" )
|
@SuppressWarnings( "rawtypes" )
|
||||||
public void testHQL(SessionFactoryScope scope) {
|
public void testListHQL(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
final List resultList = session.createQuery(
|
final List resultList = session.createQuery(
|
||||||
"select emp.phoneNumbers from Employee emp where emp.id = :EMP_ID",
|
"select emp.phoneNumbers from Employee emp where emp.id = :EMP_ID",
|
||||||
|
@ -59,7 +59,7 @@ public class ConvertedListAttributeQueryTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings( "rawtypes" )
|
@SuppressWarnings( "rawtypes" )
|
||||||
public void testCriteria(SessionFactoryScope scope) {
|
public void testListCriteria(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( session -> {
|
scope.inTransaction( session -> {
|
||||||
final CriteriaBuilder cb = session.getCriteriaBuilder();
|
final CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
final CriteriaQuery<List> q = cb.createQuery( List.class );
|
final CriteriaQuery<List> q = cb.createQuery( List.class );
|
||||||
|
@ -71,6 +71,20 @@ public class ConvertedListAttributeQueryTest {
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testArrayCriteria(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( session -> {
|
||||||
|
final CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||||
|
final CriteriaQuery<Integer[]> q = cb.createQuery( Integer[].class );
|
||||||
|
final Root<Employee> r = q.from( Employee.class );
|
||||||
|
q.multiselect( r.get( "id" ), r.get( "id" ) );
|
||||||
|
q.where( cb.equal( r.get( "id" ), 1 ) );
|
||||||
|
final Object result = session.createQuery( q ).getSingleResult();
|
||||||
|
assertThat( result ).isInstanceOf( Object[].class );
|
||||||
|
assertThat( ( (Object[]) result ) ).containsExactly( 1, 1 );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
@Entity( name = "Employee" )
|
@Entity( name = "Employee" )
|
||||||
public static class Employee {
|
public static class Employee {
|
||||||
@Id
|
@Id
|
||||||
|
|
Loading…
Reference in New Issue