从C#调用带有null的Oracle函数
我试图从我们的C#应用程序调用Oracle函数,但我得到以下错误。我想我有两个问题:从C#调用带有null的Oracle函数,c#,oracle12c,data-access-layer,odp.net,C#,Oracle12c,Data Access Layer,Odp.net,我试图从我们的C#应用程序调用Oracle函数,但我得到以下错误。我想我有两个问题: 我想调用这个函数,但有些参数在C#端可能为null,因此我不知道如何处理它们 我不知道是否需要使用OracleParameter对象上的ParameterDirection.ReturnValue将返回值添加到参数中 这就是我正在尝试的: public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, str
OracleParameter
对象上的ParameterDirection.ReturnValue
将返回值添加到参数中public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
OracleCommand cmd = null;
try
{
StringBuilder sql = new StringBuilder();
sql.Append(" pack_SomePack.func_SearchRowCount");
cmd = new OracleCommand(sql.ToString(), this.Connection);
cmd.CommandType = CommandType.StoredProcedure;
// Don't know if I should add this guy
// cmd.Parameters.Add(new OracleParameter("RowCount", OracleDbType.Int16, ParameterDirection.ReturnValue));
cmd.Parameters.Add(new OracleParameter("FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("grpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("catCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("typCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("memNbr", OracleDbType.Long, memNbr, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("SubNbr", OracleDbType.Long, SubNbr, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("searchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("statCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("showUncategorized", OracleDbType.Char, showUncategorized? "Y" : "N", ParameterDirection.Input));
cmd.Parameters.Add(new OracleParameter("debugYN", OracleDbType.Varchar2, debugYN, ParameterDirection.Input));
cmd.BindByName = true;
int activityRowCount = Convert.ToInt16(cmd.ExecuteScalar()); // Error here
return activityRowCount;
}
我的函数执行以下操作:
FUNCTION func_SearchRowCount
(
in_FromDate IN DATE,
in_ThruDate IN DATE,
in_GrpCds IN VARCHAR2,
in_CatCds IN VARCHAR2,
in_TypCds IN VARCHAR2,
in_MemNbr IN Actv.PersNbr%TYPE,
in_SubNbr IN Actv.SubNbr%TYPE,
in_SearchBy IN VARCHAR2,
in_dispActivity IN VARCHAR2,
in_StatCds IN Ams.StatCd%TYPE,
in_UncategorizedYN IN CHAR,
in_DebugYN IN CHAR
) RETURN NUMBER AS
lvnCount NUMBER;
lvsSqlStr VARCHAR2(2000);
BEGIN
lvsSqlStr := 'SELECT COUNT(*) FROM SomeTable WHERE (Include a bunch of clauses..)';
BEGIN
EXECUTE IMMEDIATE lvsSqlStr
INTO lvnCount
USING (All the parameters);
END;
RETURN lvnCount;
END func_SearchRowCount;
当运行上面的内容时,我遇到以下错误
PLS-00306:调用'FUNC_SEARCHROWCOUNT'时参数的数量或类型错误。
所有变量都绑定了正确的数量,尽管我在某处读到ODP.NET将删除带有
null
的参数,因为那里有.Value
。这是真的吗?我应该传递什么来表示该参数没有值呢?您至少需要4件事:
- 前两个:调用
和notExecuteNonQuery
,如本文所述,并创建返回值参数。下面三分之一的地方显示了这段代码ExecuteScalar
- 第三,一定要使用
,因为它是专门设计为数据库中的占位符,而DbNull.Value
仅对.NET有意义。(嗯,null
可能还可以,因为Oracle驱动程序可能足够聪明来处理它;null
是一个好习惯,因为您是显式的)。你可以这样做DbNull.Value
newOracleParameter(“typCds”,OracleDbType.Varchar2,typCds???(object)DbNull.Value,ParameterDirection.Input))代码>
- 最后,在参数上有bind by name,但是名称与参数的名称不匹配。完全匹配名称或按位置绑定
至于具体的错误,返回值是“参数”,没有正确绑定参数。Oracle需要13个参数,而您实际上没有提供任何参数。您的代码似乎有几个问题。
Oracle类型LONG与C#中的LONG不同,Oracle DB中的LONG允许您存储最大2GB大小的字符数据。在C#中,它是一种使用64位的数字类型。由于您提交的代码没有解释您在包函数的_MemNbr、_SubNbr和_statcs中的参数是什么类型的数据,因此我只能猜测它是什么,这取决于您在c方法中对参数列表的定义
“new OracleParameter(“”)语句中C#中的参数名与函数参数不完全匹配。在Pl/Sql中,您添加了一个“In#”前缀,但在c代码中删除了它。使用“cmd.BindByName=true”,您可以对ODP.Net说“嘿,按名称绑定集合中的参数,而不是使用位置”。在这种情况下,它们必须完全匹配
方法的C#返回值为int(System.Int32),PlSql包函数的返回值为NUMBER。对于没有指定刻度的数字,ODP.Net似乎以C#返回十进制。当ODP.Net试图在内部将oracle数字类型转换为short(Int16)时,可能会遇到转换/invalidcast异常。当返回的计数大于short.MaxValue时,可能会出现超出范围的异常。尝试在创建返回值参数时将Int32指定为返回值
OracleCommand实现IDisposable接口。请确保在不再需要时释放您的命令,因为对象中IDisposable接口的实现表明该对象创建/使用了一些资源(托管或非托管),并且在操作完成时必须释放这些资源。最短的方法是使用
C#的“using”关键字,它确保在代码执行离开块时调用cmd.Dispose(),而不管是否发生异常或块是否成功结束
public int GetActivityRowCount(DateTime fromDate, DateTime thruDate, string grpCds, string catCds, string typCds, long? memNbr, long? subNbr, string searchBy, string dispActivity, string statCds, bool showUncategorized, string debugYN)
{
using (var cmd = new OracleCommand("pack_SomePack.func_SearchRowCount", this.Connection))
using (var result = new OracleParameter("result", OracleDbType.Int32, ParameterDirection.ReturnValue))
using (var fromDateParam = new OracleParameter("in_FromDate", OracleDbType.Date, fromDate, ParameterDirection.Input))
using (var thruDateParam = new OracleParameter("in_ThruDate", OracleDbType.Date, thruDate, ParameterDirection.Input))
using (var grpCdsParam = new OracleParameter("in_GrpCds", OracleDbType.Varchar2, grpCds, ParameterDirection.Input))
using (var catCdsParam = new OracleParameter("in_CatCds", OracleDbType.Varchar2, catCds, ParameterDirection.Input))
using (var typCdsParam = new OracleParameter("in_TypCds", OracleDbType.Varchar2, typCds, ParameterDirection.Input))
using (var memNbrParam = new OracleParameter("in_MemNbr", OracleDbType.Int64, memNbr, ParameterDirection.Input))
using (var subNbrParam = new OracleParameter("in_SubNbr", OracleDbType.Int64, SubNbr, ParameterDirection.Input))
using (var searchByParam = new OracleParameter("in_SearchBy", OracleDbType.Varchar2, searchBy, ParameterDirection.Input))
using (var dispActivityParam = new OracleParameter("in_dispActivity", OracleDbType.Varchar2, dispActivity, ParameterDirection.Input))
using (var statCdsParam = new OracleParameter("in_StatCds", OracleDbType.Varchar2, statCds, ParameterDirection.Input))
using (var uncategorizedYnParam = new OracleParameter("in_UncategorizedYN", OracleDbType.Char, showUncategorized ? "Y" : "N", ParameterDirection.Input))
using (var debugYnParam = new OracleParameter("in_DebugYN", OracleDbType.Char, debugYN, ParameterDirection.Input))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add(result);
cmd.Parameters.Add(fromDateParam);
cmd.Parameters.Add(thruDateParam);
cmd.Parameters.Add(grpCdsParam);
cmd.Parameters.Add(catCdsParam);
cmd.Parameters.Add(typCdsParam);
cmd.Parameters.Add(memNbrParam);
cmd.Parameters.Add(subNbrParam);
cmd.Parameters.Add(searchByParam);
cmd.Parameters.Add(dispActivityParam);
cmd.Parameters.Add(statCdsParam);
cmd.Parameters.Add(uncategorizedYnParam);
cmd.Parameters.Add(debugYnParam);
cmd.BindByName = true;
cmd.ExecuteNonQuery();
return Convert.ToInt32(result.Value);
}
}
关于这个主题,我模糊的记忆告诉我,你通过在线阅读传入System.DBNull.Value
@vc74,看起来,ExecuteNonQuery
返回更新数据库时生效的行数,ExecuteScalar
在你只需要一个值时使用,比如COUNT(*)
。关于ExecuteScalar与ExecuteOnQuery,我已经尝试了上述三种方法。使用了ExecuteNonQuery
,添加到ReturnValue
参数中,还使用了?
运算符检查空值,但我仍然得到相同的错误<代码>PLS-00306:调用'FUNC_SEARCHROWCOUNT'时参数的数量或类型错误。
我想我可能会看到它,如果正确,我会更新我的答案。参数上有按名称绑定,但名称与参数名称不匹配。请尝试完全匹配名称或按位置绑定。它可能会默认所有参数(计数为零,因为没有一个参数会被绑定)。就是这样!我一直认为,BindByName
只在应用程序的C端使用。我不知道这也适用于你所说的。删除BindByName
修复了它。