在 SqlDataSource Select 命令中使用 Oracle 存储过程






4.60/5 (7投票s)
如何在 SqlDataSource Select 命令中使用 Oracle(以及其他非 Microsoft)SP
引言
在 SqlDataSource Select 命令中使用 Oracle 存储过程并非易事。 当你从 Oracle SP 返回记录集时,你必须声明一个类型为 sys_refcursor
的 out
参数,这需要在数据源上处理 Selecting 事件才能实现。
背景
为此,我将演示两种方法,一种使用简单的代码后台处理 Selecting 事件,另一种是开发自定义 Parameter 控制,并对 SqlDataSource
控制进行子类化。 后者更复杂,但它使你能够使用不仅来自 Oracle,而且来自所有返回游标的存储过程的数据库中的存储过程。
在代码后台中使用 Selecting 事件
首先,我们需要创建将从我们的应用程序调用的简单存储过程
create or replace procedure testCountries(p_rc out sys_refcursor) is
begin
open p_rc for
select * from Countries;
end testCountries;
要从 ASP.NET 页面访问此 SP,你可以创建一个如下页面
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1">
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server"
ConnectionString="<%$ ConnectionStrings:oraConnectionString %>"
ProviderName="<%$ ConnectionStrings:oraConnectionString.ProviderName %>"
SelectCommand="TESTCOUNTRIES" SelectCommandType="StoredProcedure"
onselecting="SqlDataSource1_Selecting">
<SelectParameters>
<asp:Parameter Name="p_rc" Direction="Output" />
</SelectParameters>
然后在代码后台,只需在命令对象中找到参数,并为其分配适当的类型
protected void SqlDataSource1_Selecting
(object sender, SqlDataSourceSelectingEventArgs e)
{
((System.Data.OracleClient.OracleParameter)e.Command.Parameters[0]).OracleType =
System.Data.OracleClient.OracleType.Cursor;
}
创建自定义 Parameter 和 SqlDataSource
如果你想仅使用声明性语法来做到这一点,我提出了以下方法
首先,创建一个自定义 Parameter 控制,它将保存命令对象参数的属性名称(在我们的例子中为 OracleType
),该属性名称设置参数类型,以及该属性的 enum
值(在我们的例子中为 Cursor
)。
namespace CustomComponents
{
public class DBSpecialParameter : Parameter
{
/// <summary>
/// Gets or sets the string that contains the name of the property
/// of the Parameter object which holds parameter type
/// </summary>
public string DBParamTypePropertyName
{
get { return ViewState["DBParamTypePropertyName"] !=
null ? (string)ViewState["DBParamTypePropertyName"] : string.Empty; }
set { ViewState["DBParamTypePropertyName"] = value; }
}
/// <summary>
/// The enum value which has to be assigned to the DBParamTypePropertyName
/// </summary>
public string DBParamTypeEnumeValue
{
get { return ViewState["DBParamTypeEnumeValue"] !=
null ? (string)ViewState["DBParamTypeEnumeValue"] : string.Empty; }
set { ViewState["DBParamTypeEnumeValue"] = value; }
}
}
}
接下来,我们对 SqlDataSource
进行子类化,以处理 Selecting 事件,使用反射找到适当的命令对象 Parameter,找到来自我们的 DBSpecialParameter.DBParamTypePropertyName
的属性名称,并将它的值设置为 DBSpecialParameter.DBParamTypeEnumeValue
。
这是执行此操作的代码
namespace CustomComponents
{
/// <summary>
/// Summary description for SqlDataSourceEx
/// </summary>
public class SqlDataSourceEx : System.Web.UI.WebControls.SqlDataSource
{
public SqlDataSourceEx()
{
}
/// <summary>
/// Attach a handler to Selecting event
/// </summary>
/// <param name="e"></param>
protected override void OnInit(EventArgs e)
{
base.Selecting +=
new System.Web.UI.WebControls.SqlDataSourceSelectingEventHandler(
SqlDS_Selecting);
base.OnInit(e);
}
/// <summary>
/// Finds DBSpecialParameters in SqlDataSourceEx, find parameter in the
/// Parameters collection of the command object with the same name, then using
/// reflection find DBParamTypePropertyName property in the parameter and
/// assign DBParamTypeEnumeValue to it.
/// </summary>
/// <param name="sender"></param>
/// <param name="selectingArgs"></param>
protected void SqlDS_Selecting(object sender,
System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs selectingArgs)
{
foreach (System.Web.UI.WebControls.Parameter selPar
in base.SelectParameters)
{
if (selPar is DBSpecialParameter)
{
foreach (
System.Data.Common.DbParameter commParam
in selectingArgs.Command.Parameters)
{
if (selPar.Name == commParam.ParameterName)
{
try
{
// Cast to DBSpecialParameter
DBSpecialParameter dbp = selPar as DBSpecialParameter;
if (dbp == null)
throw new ApplicationException(
String.Format(
"DBSpecialParameter error: {0}
is not DBSpecialParameter!",
selPar.Name));
// Get parameter type object
Type t = commParam.GetType();
// Get the dbType property
PropertyInfo dbTypeProperty = t.GetProperty(
dbp.DBParamTypePropertyName);
if (dbTypeProperty == null)
throw new ApplicationException(String.Format(
"DBSpecialParameter error:
No property with '{0}' name" +
"exists in '{1}'!",
dbp.DBParamTypePropertyName, t.FullName));
// Get type of the property
Type enumType = dbTypeProperty.PropertyType;
// Get the cursor type enum value
FieldInfo evalue = enumType.GetField(
dbp.DBParamTypeEnumeValue);
if (evalue == null)
throw new ApplicationException(String.Format(
"DBSpecialParameter error:
No enum value '{0}' exists" +
"in '{1}'!",
dbp.DBParamTypeEnumeValue, enumType.FullName));
// Set the dbType property to enum cursor value
dbTypeProperty.SetValue(commParam,
evalue.GetValue(enumType), null);
}
catch
{
throw;
}
break;
}
}
}
}
}
}
}
这是我们可以用来从上述相同存储过程获取数据的声明性代码
<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSourceEx1">
</asp:GridView>
<custom:SqlDataSourceEx ID="SqlDataSourceEx1" runat="server"
ConnectionString="<%$ ConnectionStrings:oraConnectionString %>"
ProviderName="<%$ ConnectionStrings:oraConnectionString.ProviderName %>"
SelectCommand="testCountries" SelectCommandType="StoredProcedure" >
<SelectParameters>
<custom:DBSpecialParameter Name="p_rc" Direction="Output"
DBParamTypePropertyName="OracleType" DBParamTypeEnumeValue="Cursor" />
</SelectParameters>
</custom:SqlDataSourceEx>
编程愉快!
历史
-
2009 年 1 月 5 日:初始发布