HHH-6304 HHH-6695 Error 'Cannot create TypedQuery for query with more than one return' with named queries

This commit is contained in:
Strong Liu 2012-07-12 11:53:27 +08:00
parent c46daa4cf0
commit 973451d5e8
3 changed files with 59 additions and 54 deletions

View File

@ -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 [" +

View File

@ -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 {

View File

@ -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();