HHH-6304 HHH-6695 Error 'Cannot create TypedQuery for query with more than one return' with named queries
This commit is contained in:
parent
c46daa4cf0
commit
973451d5e8
|
@ -300,53 +300,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
// do the translation
|
// do the translation
|
||||||
org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString );
|
org.hibernate.Query hqlQuery = getSession().createQuery( jpaqlString );
|
||||||
|
|
||||||
// make sure the query is a select -> HHH-7192
|
resultClassChecking( resultClass, hqlQuery );
|
||||||
final SessionImplementor session = unwrap( SessionImplementor.class );
|
|
||||||
final HQLQueryPlan queryPlan = session.getFactory().getQueryPlanCache().getHQLQueryPlan(
|
|
||||||
jpaqlString,
|
|
||||||
false,
|
|
||||||
session.getLoadQueryInfluencers().getEnabledFilters()
|
|
||||||
);
|
|
||||||
if ( queryPlan.getTranslators()[0].isManipulationStatement() ) {
|
|
||||||
throw new IllegalArgumentException( "Update/delete queries cannot be typed" );
|
|
||||||
}
|
|
||||||
|
|
||||||
// do some return type validation checking
|
|
||||||
if ( Object[].class.equals( resultClass ) ) {
|
|
||||||
// no validation needed
|
|
||||||
}
|
|
||||||
else if ( Tuple.class.equals( resultClass ) ) {
|
|
||||||
TupleBuilderTransformer tupleTransformer = new TupleBuilderTransformer( hqlQuery );
|
|
||||||
hqlQuery.setResultTransformer( tupleTransformer );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
final Class dynamicInstantiationClass = queryPlan.getDynamicInstantiationResultType();
|
|
||||||
if ( dynamicInstantiationClass != null ) {
|
|
||||||
if ( ! resultClass.isAssignableFrom( dynamicInstantiationClass ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Mismatch in requested result type [" + resultClass.getName() +
|
|
||||||
"] and actual result type [" + dynamicInstantiationClass.getName() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if ( hqlQuery.getReturnTypes().length == 1 ) {
|
|
||||||
// if we have only a single return expression, its java type should match with the requested type
|
|
||||||
if ( !resultClass.isAssignableFrom( hqlQuery.getReturnTypes()[0].getReturnedClass() ) ) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Type specified for TypedQuery [" +
|
|
||||||
resultClass.getName() +
|
|
||||||
"] is incompatible with query return type [" +
|
|
||||||
hqlQuery.getReturnTypes()[0].getReturnedClass() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"Cannot create TypedQuery for query with more than one return using requested result type [" +
|
|
||||||
resultClass.getName() + "]"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally, build/return the query instance
|
// finally, build/return the query instance
|
||||||
return new QueryImpl<T>( hqlQuery, this );
|
return new QueryImpl<T>( hqlQuery, this );
|
||||||
|
@ -658,7 +612,7 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
*/
|
*/
|
||||||
org.hibernate.Query namedQuery = getSession().getNamedQuery( name );
|
org.hibernate.Query namedQuery = getSession().getNamedQuery( name );
|
||||||
//TODO clean this up to avoid downcasting
|
//TODO clean this up to avoid downcasting
|
||||||
final SessionFactoryImplementor factoryImplementor = ( SessionFactoryImplementor ) entityManagerFactory.getSessionFactory();
|
final SessionFactoryImplementor factoryImplementor = entityManagerFactory.getSessionFactory();
|
||||||
final NamedSQLQueryDefinition queryDefinition = factoryImplementor.getNamedSQLQuery( name );
|
final NamedSQLQueryDefinition queryDefinition = factoryImplementor.getNamedSQLQuery( name );
|
||||||
try {
|
try {
|
||||||
if ( queryDefinition != null ) {
|
if ( queryDefinition != null ) {
|
||||||
|
@ -698,12 +652,8 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( namedQuery.getReturnTypes().length != 1 ) {
|
resultClassChecking( resultClass, namedQuery );
|
||||||
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
|
|
||||||
}
|
|
||||||
if ( !resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) {
|
|
||||||
throw buildIncompatibleException( resultClass, namedQuery.getReturnTypes()[0].getReturnedClass() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return new QueryImpl<T>( namedQuery, this );
|
return new QueryImpl<T>( namedQuery, this );
|
||||||
}
|
}
|
||||||
|
@ -716,6 +666,56 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> void resultClassChecking(Class<T> resultClass, org.hibernate.Query query) {
|
||||||
|
// make sure the query is a select -> HHH-7192
|
||||||
|
final SessionImplementor session = unwrap( SessionImplementor.class );
|
||||||
|
final HQLQueryPlan queryPlan = session.getFactory().getQueryPlanCache().getHQLQueryPlan(
|
||||||
|
query.getQueryString(),
|
||||||
|
false,
|
||||||
|
session.getLoadQueryInfluencers().getEnabledFilters()
|
||||||
|
);
|
||||||
|
if ( queryPlan.getTranslators()[0].isManipulationStatement() ) {
|
||||||
|
throw new IllegalArgumentException( "Update/delete queries cannot be typed" );
|
||||||
|
}
|
||||||
|
|
||||||
|
// do some return type validation checking
|
||||||
|
if ( Object[].class.equals( resultClass ) ) {
|
||||||
|
// no validation needed
|
||||||
|
}
|
||||||
|
else if ( Tuple.class.equals( resultClass ) ) {
|
||||||
|
TupleBuilderTransformer tupleTransformer = new TupleBuilderTransformer( query );
|
||||||
|
query.setResultTransformer( tupleTransformer );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final Class dynamicInstantiationClass = queryPlan.getDynamicInstantiationResultType();
|
||||||
|
if ( dynamicInstantiationClass != null ) {
|
||||||
|
if ( ! resultClass.isAssignableFrom( dynamicInstantiationClass ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Mismatch in requested result type [" + resultClass.getName() +
|
||||||
|
"] and actual result type [" + dynamicInstantiationClass.getName() + "]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if ( query.getReturnTypes().length == 1 ) {
|
||||||
|
// if we have only a single return expression, its java type should match with the requested type
|
||||||
|
if ( !resultClass.isAssignableFrom( query.getReturnTypes()[0].getReturnedClass() ) ) {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Type specified for TypedQuery [" +
|
||||||
|
resultClass.getName() +
|
||||||
|
"] is incompatible with query return type [" +
|
||||||
|
query.getReturnTypes()[0].getReturnedClass() + "]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new IllegalArgumentException(
|
||||||
|
"Cannot create TypedQuery for query with more than one return using requested result type [" +
|
||||||
|
resultClass.getName() + "]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private IllegalArgumentException buildIncompatibleException(Class<?> resultClass, Class<?> actualResultClass) {
|
private IllegalArgumentException buildIncompatibleException(Class<?> resultClass, Class<?> actualResultClass) {
|
||||||
return new IllegalArgumentException(
|
return new IllegalArgumentException(
|
||||||
"Type specified for TypedQuery [" +
|
"Type specified for TypedQuery [" +
|
||||||
|
|
|
@ -10,6 +10,7 @@ import javax.persistence.FieldResult;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
import javax.persistence.NamedNativeQueries;
|
import javax.persistence.NamedNativeQueries;
|
||||||
import javax.persistence.NamedNativeQuery;
|
import javax.persistence.NamedNativeQuery;
|
||||||
|
import javax.persistence.NamedQuery;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.SqlResultSetMapping;
|
import javax.persistence.SqlResultSetMapping;
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ import javax.persistence.SqlResultSetMapping;
|
||||||
resultClass = Item.class
|
resultClass = Item.class
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@NamedQuery(name = "query-construct", query = "select new Item(i.name,i.descr) from Item i")
|
||||||
//@Cache(region="Item", usage=NONSTRICT_READ_WRITE)
|
//@Cache(region="Item", usage=NONSTRICT_READ_WRITE)
|
||||||
public class Item implements Serializable {
|
public class Item implements Serializable {
|
||||||
|
|
||||||
|
|
|
@ -583,6 +583,9 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
||||||
Item itemView = em.createQuery( "select new Item(i.name,i.descr) from Item i", Item.class ).getSingleResult();
|
Item itemView = em.createQuery( "select new Item(i.name,i.descr) from Item i", Item.class ).getSingleResult();
|
||||||
assertNotNull( itemView );
|
assertNotNull( itemView );
|
||||||
assertEquals( "Micro$oft mouse", itemView.getDescr() );
|
assertEquals( "Micro$oft mouse", itemView.getDescr() );
|
||||||
|
itemView = em.createNamedQuery( "query-construct", Item.class ).getSingleResult();
|
||||||
|
assertNotNull( itemView );
|
||||||
|
assertEquals( "Micro$oft mouse", itemView.getDescr() );
|
||||||
em.remove( item );
|
em.remove( item );
|
||||||
em.getTransaction().commit();
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue