我试图在Oracle DB上调用一个简单的存储过程,该存储过程将Udt(用户定义的类型)作为输入并产生一个简单的varchar2输出。
但是,随着我不断出现以下错误,我的代码中显然存在错误:
Invalid parameter binding
at Oracle.DataAccess.Client.OracleParameter.PreBind_OracleObject(OracleConnection conn)
at Oracle.DataAccess.Client.OracleParameter.PreBind_Object(OracleConnection conn)
at Oracle.DataAccess.Client.OracleParameter.PreBind(OracleConnection conn, IntPtr errCtx, Int32 arraySize)
at Oracle.DataAccess.Client.OracleCommand.ExecuteReader(Boolean requery, Boolean fillRequest, CommandBehavior behavior)
at Oracle.DataAccess.Client.OracleCommand.ExecuteReader()
at Oracle.DataAccess.Client.OracleCommand.ExecuteScalar()
我一直在阅读Oracle文档
https://docs.oracle.com/database/121/ODPNT/extenRest.htm#ODPNT453,
https://docs.oracle.com/cd/E14435_01/win.111/e10927/featUDTs.htm#CJAHJHGE和
https://docs.oracle.com/cd/E14435_01/win.111/e10927/IOracleCustomTypeInterface.htm#BABHGCIG
并搜索各种来源:
https://www.codeproject.com/Articles/141728/Interaction-between-C-Application-and-Oracle-throu
Invalid parameter name binding oracle UDT
C# Call Oracle Stored Procedure with nested UDT
寻找线索可能出什么问题,但没有运气。
我的存储过程具有以下声明:
PROCEDURE Test2(TEST2_IN_o IN TEST2_IN, errortext_out OUT varchar2);
然后输入:
create or replace TYPE TEST2_IN AS OBJECT (
FIELD1 VARCHAR2 (50 Byte),
FIELD2 VARCHAR2 (50 Byte),
FIELD3 VARCHAR2 (20 Byte),
USER_ID VARCHAR2(20)
) NOT FINAL
这是我的对象映射:
namespace OracleProcedureTest
{
[OracleCustomTypeMapping("TEST2_IN")]
public class TEST2_IN : IOracleCustomType, INullable
{
public TEST2_IN(string Field1, string Field2, string Field3, string UserID)
{
FIELD1 = Field1;
FIELD2 = Field2;
FIELD3 = Field3;
USER_ID = UserID;
}
[OracleObjectMapping("FIELD1")]
public string FIELD1 { get; set; }
[OracleObjectMapping("FIELD2")]
public string FIELD2 { get; set; }
[OracleObjectMapping("FIELD3")]
public string FIELD3 { get; set; }
[OracleObjectMapping("USER_ID")]
public string USER_ID { get; set; }
public bool IsNull { get; set; }
public static TEST2_IN Null => new TEST2_IN { IsNull = true };
public void FromCustomObject(OracleConnection con, IntPtr pUdt)
{
OracleUdt.SetValue(con, pUdt, "FIELD1", FIELD1);
OracleUdt.SetValue(con, pUdt, "FIELD2", FIELD2);
OracleUdt.SetValue(con, pUdt, "FIELD3", FIELD3);
OracleUdt.SetValue(con, pUdt, "USER_ID", USER_ID);
}
public void ToCustomObject(OracleConnection con, IntPtr pUdt)
{
FIELD1 = ((string)(OracleUdt.GetValue(con, pUdt, "FIELD1")));
FIELD2 = ((string)(OracleUdt.GetValue(con, pUdt, "FIELD2")));
FIELD3 = ((string)(OracleUdt.GetValue(con, pUdt, "FIELD3")));
USER_ID = ((string)(OracleUdt.GetValue(con, pUdt, "USER_ID")));
}
}
}
下面是进行调用的代码:
public static void RunTestFunction2(OracleConnection connection)
{
OracleTransaction transaction = null;
OracleCommand cmd = null;
//Start transaction
transaction = connection.BeginTransaction(IsolationLevel.ReadCommitted);
//Create the command
cmd = new OracleCommand();
cmd.Connection = connection;
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "MyPackage.Test2";
//Create the input object
TEST2_IN inputObject = new TEST2_IN("Hello", "world", "OracleDB ", "123456");
//Create the input parameter
OracleParameter parameter_in = cmd.CreateParameter();
parameter_in.OracleDbType = OracleDbType.Object;
parameter_in.Direction = ParameterDirection.Input;
parameter_in.ParameterName = "TEST2_IN_o";
parameter_in.UdtTypeName = "TEST2_IN";
parameter_in.Value = inputObject;
cmd.Parameters.Add(parameter_in);
//Create output parameter
OracleParameter parameter_out = cmd.Parameters.Add("errortext_out", OracleDbType.Varchar2, 200);
parameter_out.Direction = ParameterDirection.Output;
//Run command and print result.
Oracle.DataAccess.Types.OracleString oString;
cmd.ExecuteNonQuery();
oString = (Oracle.DataAccess.Types.OracleString)parameter_out.Value;
Console.WriteLine("Return message was '" + oString.Value + "'.");
}
感谢您的帮助。
我知道用于Visual Studio的Oracle工具允许从服务器资源管理器中创建这些对象,但是我无法使其正常工作。我安装了开发人员工具,但只能看到不允许创建Udt类的托管驱动程序。
答案 0 :(得分:1)
发现了这个问题,而且就像在我的键盘和屏幕之间发生了很多次一样:
我的解决方案中有一个名为TEST2_IN的结构。计划是用结构以及类进行测试。但是,尽管我没有为该结构分配任何属性,但是oracle的反射编程将这种类型捕获为要使用的类型,而不是上面提供的类。因此,删除结构后,上述代码按计划工作了!