openJPA的用戶說明文檔中說明,在用createNativeQuery時,如果不是SELEC,則統(tǒng)一按存儲過程調(diào)用處理,但Oracle的存儲過程返回結(jié)果集的情況與MSSQL和Sybase等數(shù)據(jù)庫均不相同,它是返回一個引用游標(biāo),而不是直接返回結(jié)果集,即對CallableStatement不能直接調(diào)用executeQuery來取得結(jié)果集,而必須先用excute,然后用statement.getObject(int index)來取得結(jié)果集,因此,必須對源程序進(jìn)行修改(0.9.7-1.0.0均要改)。按openJPA的設(shè)計(jì)思想,我在DBDictionary.java中(openjpa-jdbc組件下)增加兩個方法
public class DBDictionary
implements Configurable, ConnectionDecorator, JoinSyntaxes,

LoggingConnectionDecorator.SQLWarningHandler
{



/** *//**
* register stored procedure resultset parameters
* @param stmnt
* @throws SQLException
*/

public void regStoredProcedureResultParam(CallableStatement stmnt) throws SQLException
{
}

/** *//**
* get stored procedure resultset
* @param stmt
* @return
* @throws SQLException
*/

public ResultSet getStoredProcedureOutResult(CallableStatement stmnt) throws SQLException
{
return null;
}
}
然后修改OracleDictionary.java(openjpa-jdbc組件下),具體實(shí)現(xiàn)這兩個方法
public class OracleDictionary

extends DBDictionary
{



/** *//**
* register stored procedure resultset parameters
* @param stmnt
* @throws SQLException
*/

public void regStoredProcedureResultParam(CallableStatement stmnt) throws SQLException
{
stmnt.registerOutParameter(1, -10);
}

/** *//**
* get stored procedure resultset
* @param stmt
* @return
* @throws SQLException
*/

public ResultSet getStoredProcedureOutResult(CallableStatement stmnt) throws SQLException
{
stmnt.execute();
return (ResultSet) stmnt.getObject(1);
}
}
對于其它的數(shù)據(jù)庫,請打開對應(yīng)的Dictionary.java,進(jìn)行針對性修改(我只用Oracle)
然后再修改SQLStoreQuery.java

public class SQLStoreQuery extends AbstractStoreQuery
{

private static class SQLExecutor extends AbstractExecutor
{


public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range range)
{
JDBCStore store = ((SQLStoreQuery) q).getStore();
DBDictionary dict = store.getDBDictionary();
String sql = q.getContext().getQueryString();

List paramList;

if (params.length > 0)
{
paramList = new ArrayList(Arrays.asList(params));

try
{
sql = substituteParams(sql, paramList);

} catch (IOException ioe)
{
throw new UserException(ioe);
}
} else
paramList = Collections.EMPTY_LIST;

SQLBuffer buf = new SQLBuffer(dict).append(sql);
Connection conn = store.getConnection();
JDBCFetchConfiguration fetch = (JDBCFetchConfiguration) q.getContext().getFetchConfiguration();

boolean wrcall = false;
ResultObjectProvider rop;
PreparedStatement stmnt = null;

try
{
// use the right method depending on sel vs. proc, lrs setting
if (_select && !range.lrs)
stmnt = buf.prepareStatement(conn);
else if (_select)
stmnt = buf.prepareStatement(conn, fetch, -1, -1);

else
{
// stored procedure
if (!range.lrs)
stmnt = buf.prepareCall(conn);
else
stmnt = buf.prepareCall(conn, fetch, -1, -1);
// if the stored procedure has resultset,set the out resultset param

if (q.getContext().getResultType() != null)
{
dict.regStoredProcedureResultParam((CallableStatement) stmnt);
wrcall = true;
}
}
int index = 0;
for (Iterator i = paramList.iterator(); i.hasNext();)
dict.setUnknown(stmnt, ++index, i.next(), null);

ResultSetResult res = new ResultSetResult(conn, stmnt, wrcall ? dict
.getStoredProcedureOutResult((CallableStatement) stmnt) : stmnt.executeQuery(), store);
if (_resultMapping != null)
rop = new MappedQueryResultObjectProvider(_resultMapping, store, fetch, res);
else if (q.getContext().getCandidateType() != null)
rop = new GenericResultObjectProvider((ClassMapping) _meta, store, fetch, res);
else
rop = new SQLProjectionResultObjectProvider(store, fetch, res, q.getContext().getResultType());

} catch (SQLException se)
{
if (stmnt != null)

try
{
stmnt.close();

} catch (SQLException se2)
{
}

try
{
conn.close();

} catch (SQLException se2)
{
}
throw SQLExceptions.getStore(se, dict);
}

if (range.start != 0 || range.end != Long.MAX_VALUE)
rop = new RangeResultObjectProvider(rop, range.start, range.end);
return rop;
}
用maven重新編譯和打包,即可。
用法:
EntityManager em = ...
Query q = em.createNativeQuery("{?=call a()}", A.class);
List<?> list q.getResultList();