HHH-5106 add support for SQL Named Typed-Query
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19219 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
d4de388e61
commit
38be092aae
|
@ -93,12 +93,17 @@ import org.hibernate.ejb.transaction.JoinableCMTTransaction;
|
||||||
import org.hibernate.ejb.util.CacheModeHelper;
|
import org.hibernate.ejb.util.CacheModeHelper;
|
||||||
import org.hibernate.ejb.util.ConfigurationHelper;
|
import org.hibernate.ejb.util.ConfigurationHelper;
|
||||||
import org.hibernate.ejb.util.LockModeTypeHelper;
|
import org.hibernate.ejb.util.LockModeTypeHelper;
|
||||||
|
import org.hibernate.engine.NamedSQLQueryDefinition;
|
||||||
|
import org.hibernate.engine.ResultSetMappingDefinition;
|
||||||
import org.hibernate.engine.SessionFactoryImplementor;
|
import org.hibernate.engine.SessionFactoryImplementor;
|
||||||
import org.hibernate.engine.SessionImplementor;
|
import org.hibernate.engine.SessionImplementor;
|
||||||
|
import org.hibernate.engine.query.sql.NativeSQLQueryReturn;
|
||||||
|
import org.hibernate.engine.query.sql.NativeSQLQueryRootReturn;
|
||||||
import org.hibernate.proxy.HibernateProxy;
|
import org.hibernate.proxy.HibernateProxy;
|
||||||
import org.hibernate.transaction.TransactionFactory;
|
import org.hibernate.transaction.TransactionFactory;
|
||||||
import org.hibernate.transform.BasicTransformerAdapter;
|
import org.hibernate.transform.BasicTransformerAdapter;
|
||||||
import org.hibernate.util.JTAHelper;
|
import org.hibernate.util.JTAHelper;
|
||||||
|
import org.hibernate.util.ReflectHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:gavin@hibernate.org">Gavin King</a>
|
* @author <a href="mailto:gavin@hibernate.org">Gavin King</a>
|
||||||
|
@ -449,18 +454,60 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
|
|
||||||
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
|
public <T> TypedQuery<T> createNamedQuery(String name, Class<T> resultClass) {
|
||||||
try {
|
try {
|
||||||
|
/*
|
||||||
|
* Get the named query.
|
||||||
|
* If the named query is a SQL query, get the expected returned type from the query definition
|
||||||
|
* or its associated result set mapping
|
||||||
|
* If the named query is a HQL query, use getReturnType()
|
||||||
|
*/
|
||||||
org.hibernate.Query namedQuery = getSession().getNamedQuery( name );
|
org.hibernate.Query namedQuery = getSession().getNamedQuery( name );
|
||||||
|
//TODO clean this up to avoid downcasting
|
||||||
|
final SessionFactoryImplementor factoryImplementor = ( SessionFactoryImplementor ) entityManagerFactory.getSessionFactory();
|
||||||
|
final NamedSQLQueryDefinition queryDefinition = factoryImplementor.getNamedSQLQuery( name );
|
||||||
try {
|
try {
|
||||||
|
if ( queryDefinition != null ) {
|
||||||
|
Class<?> actualReturnedClass;
|
||||||
|
|
||||||
|
final NativeSQLQueryReturn[] queryReturns;
|
||||||
|
if ( queryDefinition.getQueryReturns() != null ) {
|
||||||
|
queryReturns = queryDefinition.getQueryReturns();
|
||||||
|
}
|
||||||
|
else if ( queryDefinition.getResultSetRef() != null ) {
|
||||||
|
final ResultSetMappingDefinition rsMapping = factoryImplementor.getResultSetMapping(
|
||||||
|
queryDefinition.getResultSetRef()
|
||||||
|
);
|
||||||
|
queryReturns = rsMapping.getQueryReturns();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw new AssertionFailure( "Unsupported named query model. Please report the bug in Hibernate EntityManager");
|
||||||
|
}
|
||||||
|
if ( queryReturns.length > 1 ) {
|
||||||
|
throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" );
|
||||||
|
}
|
||||||
|
final NativeSQLQueryReturn nativeSQLQueryReturn = queryReturns[0];
|
||||||
|
if ( nativeSQLQueryReturn instanceof NativeSQLQueryRootReturn ) {
|
||||||
|
final String entityClassName = ( ( NativeSQLQueryRootReturn ) nativeSQLQueryReturn ).getReturnEntityName();
|
||||||
|
try {
|
||||||
|
actualReturnedClass = ReflectHelper.classForName( entityClassName, AbstractEntityManagerImpl.class );
|
||||||
|
}
|
||||||
|
catch ( ClassNotFoundException e ) {
|
||||||
|
throw new AssertionFailure( "Unable to instantiate class declared on named native query: " + name + " " + entityClassName );
|
||||||
|
}
|
||||||
|
if ( !resultClass.isAssignableFrom( actualReturnedClass ) ) {
|
||||||
|
throw buildIncompatibleException( resultClass, actualReturnedClass );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
//TODO support other NativeSQLQueryReturn type. For now let it go.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
if ( namedQuery.getReturnTypes().length != 1 ) {
|
if ( namedQuery.getReturnTypes().length != 1 ) {
|
||||||
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" );
|
||||||
}
|
}
|
||||||
if ( !resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) {
|
if ( !resultClass.isAssignableFrom( namedQuery.getReturnTypes()[0].getReturnedClass() ) ) {
|
||||||
throw new IllegalArgumentException(
|
throw buildIncompatibleException( resultClass, namedQuery.getReturnTypes()[0].getReturnedClass() );
|
||||||
"Type specified for TypedQuery [" +
|
}
|
||||||
resultClass.getName() +
|
|
||||||
"] is incompatible with query return type [" +
|
|
||||||
namedQuery.getReturnTypes()[0].getReturnedClass() + "]"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
return new QueryImpl<T>( namedQuery, this );
|
return new QueryImpl<T>( namedQuery, this );
|
||||||
}
|
}
|
||||||
|
@ -473,6 +520,15 @@ public abstract class AbstractEntityManagerImpl implements HibernateEntityManage
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IllegalArgumentException buildIncompatibleException(Class<?> resultClass, Class<?> actualResultClass) {
|
||||||
|
return new IllegalArgumentException(
|
||||||
|
"Type specified for TypedQuery [" +
|
||||||
|
resultClass.getName() +
|
||||||
|
"] is incompatible with query return type [" +
|
||||||
|
actualResultClass + "]"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public Query createNativeQuery(String sqlString) {
|
public Query createNativeQuery(String sqlString) {
|
||||||
try {
|
try {
|
||||||
SQLQuery q = getSession().createSQLQuery( sqlString );
|
SQLQuery q = getSession().createSQLQuery( sqlString );
|
||||||
|
|
|
@ -9,6 +9,9 @@ import javax.persistence.Entity;
|
||||||
import javax.persistence.EntityResult;
|
import javax.persistence.EntityResult;
|
||||||
import javax.persistence.FieldResult;
|
import javax.persistence.FieldResult;
|
||||||
import javax.persistence.Id;
|
import javax.persistence.Id;
|
||||||
|
import javax.persistence.NamedNativeQueries;
|
||||||
|
import javax.persistence.NamedNativeQuery;
|
||||||
|
import javax.persistence.NamedQuery;
|
||||||
import javax.persistence.OneToMany;
|
import javax.persistence.OneToMany;
|
||||||
import javax.persistence.SqlResultSetMapping;
|
import javax.persistence.SqlResultSetMapping;
|
||||||
|
|
||||||
|
@ -16,12 +19,24 @@ import javax.persistence.SqlResultSetMapping;
|
||||||
* @author Gavin King
|
* @author Gavin King
|
||||||
*/
|
*/
|
||||||
@Entity(name = "Item")
|
@Entity(name = "Item")
|
||||||
@SqlResultSetMapping(name = "getItem", entities =
|
@SqlResultSetMapping(name = "getItem", entities =
|
||||||
@EntityResult(entityClass = org.hibernate.ejb.test.Item.class, fields = {
|
@EntityResult(entityClass = org.hibernate.ejb.test.Item.class, fields = {
|
||||||
@FieldResult(name = "name", column = "itemname"),
|
@FieldResult(name = "name", column = "itemname"),
|
||||||
@FieldResult(name = "descr", column = "itemdescription")
|
@FieldResult(name = "descr", column = "itemdescription")
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
|
@NamedNativeQueries({
|
||||||
|
@NamedNativeQuery(
|
||||||
|
name = "nativeItem1",
|
||||||
|
query = "select name as itemname, descr as itemdescription from Item",
|
||||||
|
resultSetMapping = "getItem"
|
||||||
|
),
|
||||||
|
@NamedNativeQuery(
|
||||||
|
name = "nativeItem2",
|
||||||
|
query = "select * from Item",
|
||||||
|
resultClass = Item.class
|
||||||
|
)
|
||||||
|
})
|
||||||
//@Cache(region="Item", usage=NONSTRICT_READ_WRITE)
|
//@Cache(region="Item", usage=NONSTRICT_READ_WRITE)
|
||||||
public class Item implements Serializable {
|
public class Item implements Serializable {
|
||||||
|
|
||||||
|
|
|
@ -435,6 +435,26 @@ public class QueryTest extends TestCase {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void testTypedNamedNativeQuery() {
|
||||||
|
Item item = new Item( "Mouse", "Micro$oft mouse" );
|
||||||
|
|
||||||
|
EntityManager em = getOrCreateEntityManager();
|
||||||
|
em.getTransaction().begin();
|
||||||
|
em.persist( item );
|
||||||
|
assertTrue( em.contains( item ) );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.getTransaction().begin();
|
||||||
|
item = em.createNamedQuery( "nativeItem1", Item.class ).getSingleResult();
|
||||||
|
item = em.createNamedQuery( "nativeItem2", Item.class ).getSingleResult();
|
||||||
|
assertNotNull( item );
|
||||||
|
assertEquals( "Micro$oft mouse", item.getDescr() );
|
||||||
|
em.remove( item );
|
||||||
|
em.getTransaction().commit();
|
||||||
|
|
||||||
|
em.close();
|
||||||
|
}
|
||||||
|
|
||||||
public Class[] getAnnotatedClasses() {
|
public Class[] getAnnotatedClasses() {
|
||||||
return new Class[]{
|
return new Class[]{
|
||||||
Item.class,
|
Item.class,
|
||||||
|
|
Loading…
Reference in New Issue