VO高階使用技巧之二:程式設計實現基於Ref Cursor的VO
阿新 • • 發佈:2019-02-01
開發執行環境:JDevloper 11.1.2.4.0+ Oracle Database 11gR2 XE
本文最後一次修改日期:2013-07-01
在Fusion Order Demo的StandaloneExamples中的AdvancedViewObjectsExamples中的ViewObjectOnRefCursor,介紹瞭如何使用ResultSet查詢結果集實現View Object。
其中,Ref Cursor是使用PL-SQL實現的。
關於Fusion Order Demo,請參考《釋出與執行 Oracle Fusion Order Demo》。
關於VO中的重要方法的介紹,請參考《VO高階使用技巧之一:可重寫的重要的方法 》。
1. PL-SQL程式碼
REM For security reasons, the FOD user is not given create procedure privileges
REM To run this script, issue the following statement as system:
REM grant create procedure to fod;
REM To back out this change, issue the following as FOD:
REM drop package RefCursorExample;
REM And run the following as system:
REM revoke create procedure from fod;
CREATE OR REPLACE PACKAGE RefCursorExample IS
TYPE ref_cursor IS REF CURSOR;
FUNCTION get_orders_for_customer(p_email VARCHAR2) RETURN ref_cursor;
FUNCTION count_orders_for_customer(p_email VARCHAR2) RETURN NUMBER;
END RefCursorExample;
.
/
show errors
CREATE OR REPLACE PACKAGE BODY RefCursorExample IS
FUNCTION get_orders_for_customer(p_email VARCHAR2) RETURN ref_cursor IS
the_cursor ref_cursor;
BEGIN
OPEN the_cursor FOR
SELECT o.order_id, o.order_status_code, o.order_total
FROM orders o, persons p
WHERE o.customer_id = p.person_id
AND p.email = p_email;
RETURN the_cursor;
END get_orders_for_customer;
FUNCTION count_orders_for_customer(p_email VARCHAR2) RETURN NUMBER IS
the_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO the_count
FROM orders o, persons p
WHERE o.customer_id = p.person_id
AND p.email = p_email;
RETURN the_count;
END count_orders_for_customer;
END RefCursorExample;
.
/
show errors
2. OrdersForCustomerImpl.java程式碼
package devguide.advanced.refcursor;
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.sql.Timestamp;
import oracle.jbo.JboException;
import oracle.jbo.domain.Date;
import oracle.jbo.domain.Number;
import oracle.jbo.server.SQLBuilder;
import oracle.jbo.server.ViewObjectImpl;
import oracle.jbo.server.ViewRowImpl;
import oracle.jbo.server.ViewRowSetImpl;
import oracle.jdbc.OracleTypes;
// ---------------------------------------------------------------------
// --- File generated by Oracle ADF Business Components Design Time.
// --- Custom code may be added to this class.
// --- Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
public class OrdersForCustomerImpl extends ViewObjectImpl {
/**This is the default constructor (do not remove).
*/
public OrdersForCustomerImpl() {
}
/**
* Overridden framework method.
*
* Executed when the framework needs to issue the database query for
* the query collection based on this view object. One view object
* can produce many related result sets, each potentially the result
* of different bind variable values. If the rowset in query is involved
* in a framework-coordinated master/detail viewlink, then the params array
* will contain one or more framework-supplied bind parameters. If there
* are any user-supplied bind parameter values, they will *PRECEED* the
* framework-supplied bind variable values in the params array, and the
* number of user parameters will be indicated by the value of the
* numUserParams argument.
*/
protected void executeQueryForCollection(Object qc, Object[] params, int numUserParams) {
storeNewResultSet(qc, retrieveRefCursor(qc, params));
super.executeQueryForCollection(qc, params, numUserParams);
}
/**
* Overridden framework method.
*
* Wipe out all traces of a built-in query for this VO
*/
protected void create() {
getViewDef().setQuery(null);
getViewDef().setSelectClause(null);
setQuery(null);
}
/**
* Overridden framework method.
*
* The role of this method is to "fetch", populate, and return a single row
* from the datasource by calling createNewRowForCollection() and populating
* its attributes using populateAttributeForRow().
*/
protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet rs) {
/*
* We ignore the JDBC ResultSet passed by the framework (null anyway) and
* use the resultset that we've stored in the query-collection-private
* user data storage
*/
rs = getResultSet(qc);
/*
* Create a new row to populate
*/
ViewRowImpl r = createNewRowForCollection(qc);
try {
/*
* Populate new row by attribute slot number for current row in Result Set
*/
populateAttributeForRow(r, 0, rs.getLong(1));
populateAttributeForRow(r, 1, rs.getString(2));
populateAttributeForRow(r, 2, rs.getString(3));
} catch (SQLException s) {
throw new JboException(s);
}
return r;
}
/**
* Overridden framework method.
*
* Return true if the datasource has at least one more record to fetch.
*/
protected boolean hasNextForCollection(Object qc) {
ResultSet rs = getResultSet(qc);
boolean nextOne = false;
try {
nextOne = rs.next();
/*
* When were at the end of the result set, mark the query collection
* as "FetchComplete".
*/
if (!nextOne) {
setFetchCompleteForCollection(qc, true);
/*
* Close the result set, we're done with it
*/
rs.close();
}
} catch (SQLException s) {
throw new JboException(s);
}
return nextOne;
}
/**
* Overridden framework method.
*
* The framework gives us a chance to clean up any resources related
* to the datasource when a query collection is done being used.
*/
protected void releaseUserDataForCollection(Object qc, Object rs) {
/*
* Ignore the ResultSet passed in since we've created our own.
* Fetch the ResultSet from the User-Data context instead
*/
ResultSet userDataRS = getResultSet(qc);
if (userDataRS != null) {
try {
userDataRS.close();
} catch (SQLException s) {
/* Ignore */
}
}
super.releaseUserDataForCollection(qc, rs);
}
/**
* Overridden framework method
*
* Return the number of rows that would be returned by executing
* the query implied by the datasource. This gives the developer a
* chance to perform a fast count of the rows that would be retrieved
* if all rows were fetched from the database. In the default implementation
* the framework will perform a SELECT COUNT(*) FROM (...) wrapper query
* to let the database return the count. This count might only be an estimate
* depending on how resource-intensive it would be to actually count the rows.
*/
public long getQueryHitCount(ViewRowSetImpl viewRowSet) {
Long result =
(Long)callStoredFunction(NUMBER, "RefCursorExample.count_orders_for_customer(?)", viewRowSet.getParameters(true));
return result.longValue();
}
// ------------- PRIVATE METHODS ----------------
/**
* Return a JDBC ResultSet representing the REF CURSOR return
* value from our stored package function.
*/
private ResultSet retrieveRefCursor(Object qc, Object[] params) {
ResultSet rs =
(ResultSet)callStoredFunction(OracleTypes.CURSOR, "RefCursorExample.get_orders_for_customer(?)", new Object[] { getNamedBindParamValue("CustEmail",
params) });
return rs;
}
private Object getNamedBindParamValue(String varName, Object[] params) {
Object result = null;
if (getBindingStyle() == SQLBuilder.BINDING_STYLE_ORACLE_NAME) {
if (params != null) {
for (Object param : params) {
Object[] nameValue = (Object[])param;
String name = (String)nameValue[0];
if (name.equals(varName)) {
本文最後一次修改日期:2013-07-01
在Fusion Order Demo的StandaloneExamples中的AdvancedViewObjectsExamples中的ViewObjectOnRefCursor,介紹瞭如何使用ResultSet查詢結果集實現View Object。
其中,Ref Cursor是使用PL-SQL實現的。
關於Fusion Order Demo,請參考《釋出與執行 Oracle Fusion Order Demo》。
關於VO中的重要方法的介紹,請參考《VO高階使用技巧之一:可重寫的重要的方法
1. PL-SQL程式碼
REM For security reasons, the FOD user is not given create procedure privileges
REM To run this script, issue the following statement as system:
REM grant create procedure to fod;
REM To back out this change, issue the following as FOD:
REM drop package RefCursorExample;
REM And run the following as system:
REM revoke create procedure from fod;
CREATE OR REPLACE PACKAGE RefCursorExample IS
TYPE ref_cursor IS REF CURSOR;
FUNCTION get_orders_for_customer(p_email VARCHAR2) RETURN ref_cursor;
FUNCTION count_orders_for_customer(p_email VARCHAR2) RETURN NUMBER;
END RefCursorExample;
.
/
show errors
CREATE OR REPLACE PACKAGE BODY RefCursorExample IS
FUNCTION get_orders_for_customer(p_email VARCHAR2) RETURN ref_cursor IS
the_cursor ref_cursor;
BEGIN
OPEN the_cursor FOR
SELECT o.order_id, o.order_status_code, o.order_total
FROM orders o, persons p
WHERE o.customer_id = p.person_id
AND p.email = p_email;
RETURN the_cursor;
END get_orders_for_customer;
FUNCTION count_orders_for_customer(p_email VARCHAR2) RETURN NUMBER IS
the_count NUMBER;
BEGIN
SELECT COUNT(*)
INTO the_count
FROM orders o, persons p
WHERE o.customer_id = p.person_id
AND p.email = p_email;
RETURN the_count;
END count_orders_for_customer;
END RefCursorExample;
.
/
show errors
2. OrdersForCustomerImpl.java程式碼
package devguide.advanced.refcursor;
import java.math.BigDecimal;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.sql.Timestamp;
import oracle.jbo.JboException;
import oracle.jbo.domain.Date;
import oracle.jbo.domain.Number;
import oracle.jbo.server.SQLBuilder;
import oracle.jbo.server.ViewObjectImpl;
import oracle.jbo.server.ViewRowImpl;
import oracle.jbo.server.ViewRowSetImpl;
import oracle.jdbc.OracleTypes;
// ---------------------------------------------------------------------
// --- File generated by Oracle ADF Business Components Design Time.
// --- Custom code may be added to this class.
// --- Warning: Do not modify method signatures of generated methods.
// ---------------------------------------------------------------------
public class OrdersForCustomerImpl extends ViewObjectImpl {
/**This is the default constructor (do not remove).
*/
public OrdersForCustomerImpl() {
}
/**
* Overridden framework method.
*
* Executed when the framework needs to issue the database query for
* the query collection based on this view object. One view object
* can produce many related result sets, each potentially the result
* of different bind variable values. If the rowset in query is involved
* in a framework-coordinated master/detail viewlink, then the params array
* will contain one or more framework-supplied bind parameters. If there
* are any user-supplied bind parameter values, they will *PRECEED* the
* framework-supplied bind variable values in the params array, and the
* number of user parameters will be indicated by the value of the
* numUserParams argument.
*/
protected void executeQueryForCollection(Object qc, Object[] params, int numUserParams) {
storeNewResultSet(qc, retrieveRefCursor(qc, params));
super.executeQueryForCollection(qc, params, numUserParams);
}
/**
* Overridden framework method.
*
* Wipe out all traces of a built-in query for this VO
*/
protected void create() {
getViewDef().setQuery(null);
getViewDef().setSelectClause(null);
setQuery(null);
}
/**
* Overridden framework method.
*
* The role of this method is to "fetch", populate, and return a single row
* from the datasource by calling createNewRowForCollection() and populating
* its attributes using populateAttributeForRow().
*/
protected ViewRowImpl createRowFromResultSet(Object qc, ResultSet rs) {
/*
* We ignore the JDBC ResultSet passed by the framework (null anyway) and
* use the resultset that we've stored in the query-collection-private
* user data storage
*/
rs = getResultSet(qc);
/*
* Create a new row to populate
*/
ViewRowImpl r = createNewRowForCollection(qc);
try {
/*
* Populate new row by attribute slot number for current row in Result Set
*/
populateAttributeForRow(r, 0, rs.getLong(1));
populateAttributeForRow(r, 1, rs.getString(2));
populateAttributeForRow(r, 2, rs.getString(3));
} catch (SQLException s) {
throw new JboException(s);
}
return r;
}
/**
* Overridden framework method.
*
* Return true if the datasource has at least one more record to fetch.
*/
protected boolean hasNextForCollection(Object qc) {
ResultSet rs = getResultSet(qc);
boolean nextOne = false;
try {
nextOne = rs.next();
/*
* When were at the end of the result set, mark the query collection
* as "FetchComplete".
*/
if (!nextOne) {
setFetchCompleteForCollection(qc, true);
/*
* Close the result set, we're done with it
*/
rs.close();
}
} catch (SQLException s) {
throw new JboException(s);
}
return nextOne;
}
/**
* Overridden framework method.
*
* The framework gives us a chance to clean up any resources related
* to the datasource when a query collection is done being used.
*/
protected void releaseUserDataForCollection(Object qc, Object rs) {
/*
* Ignore the ResultSet passed in since we've created our own.
* Fetch the ResultSet from the User-Data context instead
*/
ResultSet userDataRS = getResultSet(qc);
if (userDataRS != null) {
try {
userDataRS.close();
} catch (SQLException s) {
/* Ignore */
}
}
super.releaseUserDataForCollection(qc, rs);
}
/**
* Overridden framework method
*
* Return the number of rows that would be returned by executing
* the query implied by the datasource. This gives the developer a
* chance to perform a fast count of the rows that would be retrieved
* if all rows were fetched from the database. In the default implementation
* the framework will perform a SELECT COUNT(*) FROM (...) wrapper query
* to let the database return the count. This count might only be an estimate
* depending on how resource-intensive it would be to actually count the rows.
*/
public long getQueryHitCount(ViewRowSetImpl viewRowSet) {
Long result =
(Long)callStoredFunction(NUMBER, "RefCursorExample.count_orders_for_customer(?)", viewRowSet.getParameters(true));
return result.longValue();
}
// ------------- PRIVATE METHODS ----------------
/**
* Return a JDBC ResultSet representing the REF CURSOR return
* value from our stored package function.
*/
private ResultSet retrieveRefCursor(Object qc, Object[] params) {
ResultSet rs =
(ResultSet)callStoredFunction(OracleTypes.CURSOR, "RefCursorExample.get_orders_for_customer(?)", new Object[] { getNamedBindParamValue("CustEmail",
params) });
return rs;
}
private Object getNamedBindParamValue(String varName, Object[] params) {
Object result = null;
if (getBindingStyle() == SQLBuilder.BINDING_STYLE_ORACLE_NAME) {
if (params != null) {
for (Object param : params) {
Object[] nameValue = (Object[])param;
String name = (String)nameValue[0];
if (name.equals(varName)) {