我正在尝试从我们的C#应用程序调用Oracle函数,但是我遇到以下错误。我认为我有两个问题:
我想调用此函数,但是C#端的某些参数可以为null,因此我不知道如何处理它们。
我不知道是否需要在ParameterDirection.ReturnValue
对象上使用OracleParameter
将返回值添加到参数中。
这是我正在尝试的:
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: wrong number or types of arguments in call to 'FUNC_SEARCHROWCOUNT'
所有变量都绑定有正确的数量,尽管我读到某个地方ODP.NET将在null
处使用.Value
删除参数。这是真的?我应该传递什么来指示该参数没有值?
答案 0 :(得分:1)
您至少需要四件事:
ExecuteNonQuery
而不是ExecuteScalar
并创建返回值参数。在Accessing Oracle 9i Stored Procedures的大约三分之一处,它显示了这段代码并说您以与存储过程相同的方式执行功能。使用ParameterDirection.ReturnValue参数获取该函数返回的结果。
DbNull.Value
,因为它是为数据库中represent null values的占位符而专门设计的,而null
仅对.NET有意义。 (嗯,null
可能还可以,因为Oracle驱动程序可能足够聪明来处理它; DbNull.Value
是一个好习惯,尽管因为您很明确)。您可以做类似的事情 new OracleParameter("typCds", OracleDbType.Varchar2, typCds ?? (object)DbNull.Value, ParameterDirection.Input));
对于特定错误,返回值是“参数”,并且未正确绑定参数。 Oracle需要13个参数,而您实际上没有给它。
答案 1 :(得分:1)
您的代码似乎有几个问题。 Oracle Type LONG与C#中的LONG不同,Oracle DB中的LONG允许您存储最大2GB的字符数据。在C#中,它是使用64位的数字类型。由于您提交的代码无法说明包函数中的参数in_MemNbr,in_SubNbr和in_StatCds是什么类型的数据,我只能猜测,这取决于您在c#方法中参数列表的定义。
您在C#中的“新OracleParameter(“”)”语句中的参数名称与函数参数不完全匹配。在Pl / Sql中,您添加了“ in_”前缀,但在c#代码中将其删除。使用“ cmd.BindByName = true;”您对ODP.Net说:“嘿,通过名称而不是使用位置绑定集合中的参数”。在这种情况下,它们必须完全匹配。
方法的C#返回值为int(System.Int32),PlSql包函数的返回值为NUMBER。如果数字没有指定的小数位数,ODP.Net似乎在C#中返回小数。当ODP.Net尝试在内部将oracle数字类型转换为short(Int16)时,您可能会遇到转换/无效广播异常。当返回的计数大于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);
}
}