looking for some help in identifying the correct method of calling an Oracle Procedure call from the given info below. I am using .NET 4 with Oracle.DataAccess.Client.
Below are the details of the Procedure from Oracle:
CREATE OR REPLACE PACKAGE APPS.syk_serial_num_details
AS
TYPE account_rec_type IS RECORD(
inv_item_id NUMBER
,item_num VARCHAR2(40)
,item_desc VARCHAR2(240)
,acc_num VARCHAR2(30)
,ship_to VARCHAR2(1000)
,bill_to VARCHAR2(1000)
);
TYPE account_set IS TABLE OF account_rec_type;
PROCEDURE get_prod_details(
p_serial_num IN VARCHAR2
,p_acc_nums IN VARCHAR2
,p_ship_tos IN VARCHAR2
,p_acc_set OUT syk_serial_num_details.account_set
,p_status OUT VARCHAR2
);
END syk_serial_num_details
here are some more details showing the param types and size...below is an example of the procedure call from Toad interface:
DECLARE
l_serial_num csi_item_instances.serial_number%type;
l_acc_nums VARCHAR2(100);
l_ship_tos VARCHAR2(100);
l_acc_set syk_serial_num_details.account_set;
l_status VARCHAR2(80);
BEGIN
l_serial_num := '1025200453';
l_acc_nums := '8165';
l_ship_tos := '10332';
l_acc_set := syk_serial_num_details.account_set();
syk_serial_num_details.get_prod_details(p_serial_num => l_serial_num
,p_acc_nums => l_acc_nums
,p_ship_tos => l_ship_tos
,p_acc_set => l_acc_set
,p_status => l_status
);
Dbms_output.put_line('Status ::' || l_status);
IF(l_acc_set.count >0) then
FOR i IN 1 .. l_acc_set.count
LOOP
l_acc_set.extend;
DBMS_OUTPUT.put_line( 'Item_Number:'
|| l_acc_set(i).item_num||'|'
|| ' Desc:'
|| l_acc_set(i).item_desc||'|'
|| ' Accunt Number:'
|| l_acc_set(i).acc_num||'|'
|| ' Ship To:'
|| l_acc_set(i).ship_to||'|'
|| ' Bill To:'
|| l_acc_set(i).bill_to||'|'
);
END LOOP;
end if;
END;
So...I am having LOTS of trouble trying to identify the proper type for the p_acc_set output.
Below is my current C# code:
OracleConnection conn = getOracleConnection();
List<AccountSearchResultsDto> ProductInfoList = new List<AccountSearchResultsDto>();
using (conn)
{
conn.Open();
using (OracleCommand cmd = new OracleCommand("syk_serial_num_details.get_prod_details", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
//ASSIGN PARAMETERS TO BE PASSED
OracleParameter param1 = new OracleParameter("p_serial_num", OracleDbType.Varchar2);
param1.Direction = ParameterDirection.Input;
param1.Size = 100;
param1.Value = "1025200453";
cmd.Parameters.Add(param1);
OracleParameter param2 = new OracleParameter("p_acc_nums", OracleDbType.Varchar2);
param2.Direction = ParameterDirection.Input;
param2.Size = 100;
param2.Value = "8165";
cmd.Parameters.Add(param2);
OracleParameter param3 = new OracleParameter("p_ship_tos", OracleDbType.Varchar2);
param3.Direction = ParameterDirection.Input;
param3.Size = 100;
param3.Value = "10332";
cmd.Parameters.Add(param3);
//PARAMETERS USED TO RETURN RESULT OF PROCEDURE CALL
OracleParameter param4 = new OracleParameter("p_acc_set", OracleDbType.Object);
param4.Direction = ParameterDirection.Output;
param4.Size = 1;
cmd.Parameters.Add(param4);
OracleParameter param5 = new OracleParameter("p_status", OracleDbType.Varchar2);
param5.Direction = ParameterDirection.Output;
param5.Size = 300;
cmd.Parameters.Add(param5);
cmd.ExecuteNonQuery();
if (cmd.Parameters["p_status"].Value.ToString().Equals("SUCCESS"))
{
//Get results from p_acct_set and put values in list
}
}
}
As of now - attempting the above I am getting the following error:
Invalid parameter binding
Parameter name: p_acc_set
Should i be using the OracleParameter UdtTypeName reference for the p_acc_set?
I am very new to Oracle Procedure calls so please forgive my inexperience.
Any help is appreciated! thanks in advance!!
-R
The difference i spotted for parameter "p_acc_set" and "p_status" compare to others is that they did not assign Size on them please try to assign size on them and should fix your issue
I did not find the MSDN explaining very clearly on OracleParamter.Size property. But i did notice a line in the remarks that says
The line is taken from MSDN remarks :
For bidirectional and output parameters, and return values, you must
set the value of Size.
There's the property BindByName of OracleCommand class (defaulted to false) to handle this.
You should set it to true before executing the command to avoid that error!
for further informations read this too!!
Edit
Sorry, I didn't notice there was a PL/SQL Nested Table!! I don't think that Oracle supports a bind for that (especially if it contains records instead of simple values).
Associative Arrays, PL/SQL Nested tables and PL/SQL Vararrays are very similar data types so probably here they intend all the three things with the name Associative Arrays.
Using a Nested Table of User defined Types in place of it should solve your problem but it will become very trivial to handle for a newbie ...If so you should redefine the procedure to use the new data type and setting UdtTypeName parameter in the C# code is not the only thing to do.
Related
I am trying to INSERT my data into two tables Services and Service-line
Explaining my stored procedure:
It checks for existing ID in the Form
If not found it creates a new record in the Services table the info in the Form, then gets the ID using scope_identity and uses the ID for the Service-Line table.
Also the ID is returned to the Form and stays tre.
Later while inserting second record in Service-Line, the stored procedure checks for existing ID; if found, this time, it takes the ID from the Form and uses it in the Service-Line
This Is my stored procedure
please bear with me, as I am working in this code and testing, a lot of line are commented out
ALTER PROCEDURE [dbo].[InsertServiceServiceLine] (
--Services Entry
--FOR IF CONDITION ---CHECK THE DEFAULT VALUE IN THE FORM on SID
#ExistingSID int,
--SEELCT PARAMETES DEF VALUES
#ComboBoxSelectedBike varchar(100),
-- INPUT PARAMETERES FOR NEW RECORD
#CID int,
#Status bit = 1,
#CurrentMeter int,
#Labor decimal(20,0),
#GrandTotal decimal(20,0) = ISNULL,
--#NextService datetime,
--Service Line
#Spare nvarchar(500),
#Quantity int,
#Uprice decimal(20,2),
#Subtotal decimal(20,2)
)
AS
BEGIN
IF (#ExistingSID <= 0)
BEGIN
SET NOCOUNT ON;
DECLARE #BikeID int
SELECT #BikeID = (SELECT BikeID FROM TblBikeNames WHERE BikeName = #ComboBoxSelectedBike)
INSERT INTO [AutoDB_Sample].[dbo].[TblServices]
(CID,BikeID,Status,CurrentMeter,Labor,DateOfService)
VALUES
(#CID,#BikeID,#Status,#CurrentMeter,#Labor,GETDATE())
DECLARE #SID int
SET #SID = SCOPE_IDENTITY()
INSERT INTO [AutoDB_Sample].[dbo].[TblServiceLine]
(SID,Spare,Quantity,Uprice,Subtotal,DateCreated)
VALUES
(#SID,#Spare,#Quantity,#Uprice,#Subtotal,GETDATE())
RETURN #SID
END
ELSE
BEGIN
INSERT INTO [AutoDB_Sample].[dbo].[TblServiceLine]
(SID,Spare,Quantity,Uprice,Subtotal,DateCreated)
VALUES
(#ExistingSID,#Spare,#Quantity,#Uprice,#Subtotal,GETDATE())
END
END
It gives me an error when I use this stored procedure in a C# Windows Forms
Procedure or Function has too many Arguments
Here's a screenshot of the error
I thought that Putting my login in SP would be great and improve the performance of my application. But now am stuck.
This is my C# Code
public void AddItemIntoServices_ServiceLine()
{
ConnectionStringSettings consetting = ConfigurationManager.ConnectionStrings["AutoDB"];
String ConnectionString = consetting.ConnectionString;
SqlConnection con = new SqlConnection(ConnectionString);
try
{
con.Open(); // open the connection
// Specify the name of the Stored Procedure you will call
String SP_Name = "InsertServiceServiceLine";
// Create the SQL Command object and specify that this is a SP.
SqlCommand cmd = new SqlCommand(SP_Name, con);
cmd.CommandType = CommandType.StoredProcedure;
// Specify values for the input parameters of our Stored Procedure
// Parameters MUST be named the same as the parameters defined in the Stored Procedure.
//~~ If Condition Parameter ****************************************************************************~~//
int exitstingSID;
if (int.TryParse(LblSID_Data.Text, out exitstingSID)) ;
SqlParameter ExistingSID = new SqlParameter("#ExistingSID", exitstingSID);
ExistingSID.Direction = ParameterDirection.Input;
ExistingSID.DbType = DbType.Int16;
cmd.Parameters.Add(ExistingSID);
//Parameter to select Bike ID from Selected Bike Name
SqlParameter ParamBikeID = new SqlParameter("#ComboBoxSelectedBike", ComboBx_BikeNames.Text);
ParamBikeID.Direction = ParameterDirection.Input;
ParamBikeID.DbType = DbType.String;
cmd.Parameters.Add(ParamBikeID);
//~~ Customer Info ************************************************************************************~~//
//CID Convertion
int P_CID;
if (int.TryParse(LblCID_Data.Text, out P_CID)) ;
cmd.Parameters.AddWithValue("#CID", P_CID);
cmd.Parameters.AddWithValue("#Cname", this.TxtBx_CustomerName.Text);
cmd.Parameters.AddWithValue("#Vnum", this.TxtBx_VehicleNumber.Text);
//~~ Service Info ************************************************************************************~~//
//Labor Convertion
int Laborint;
if (int.TryParse(TxtBxLabor.Text, out Laborint)) ;
SqlParameter ParamLabor = new SqlParameter("#Labor", Laborint);
ParamLabor.Direction = ParameterDirection.Input;
ParamLabor.DbType = DbType.Int16;
cmd.Parameters.Add(ParamLabor);
//CurrentMeterConversion
int currentMeterint;
if (int.TryParse(TxtBx_CurrentMeter.Text, out currentMeterint)) ;
SqlParameter ParamCurrentMeter = new SqlParameter("#CurrentMeter", currentMeterint);
ParamCurrentMeter.Direction = ParameterDirection.Input;
ParamCurrentMeter.DbType = DbType.Int16;
cmd.Parameters.Add(ParamCurrentMeter);
//Return Value
SqlParameter ParamReturn = new SqlParameter("#SID", SqlDbType.Int);
ParamReturn.Direction = ParameterDirection.Output;
ParamReturn.DbType = DbType.Int16;
cmd.Parameters.Add(ParamReturn);
//~~ Service Info ************************************************************************************~~//
//Converstions
Decimal UP, ST;
if (Decimal.TryParse(TxtBx_UnitPrice.Text, out UP)) ;
if (Decimal.TryParse(TxtBxTotal.Text, out ST)) ;
//SpareName
cmd.Parameters.AddWithValue("#Spare", ComboBx_SparesName.Text);
//Quantity
cmd.Parameters.AddWithValue("#Qty", NumericBx_Quantity.Value);
//Unit Price
SqlParameter ParamUp = new SqlParameter("#Uprice", UP);
ParamUp.Direction = ParameterDirection.Input;
ParamUp.DbType = DbType.Decimal;
cmd.Parameters.Add(ParamUp);
//Total
SqlParameter ParamTot = new SqlParameter("Subtotal", ST);
ParamTot.Direction = ParameterDirection.Input;
ParamTot.DbType = DbType.Decimal;
cmd.Parameters.Add(ParamTot);
cmd.ExecuteNonQuery();
String _returnedSID = cmd.Parameters["#SID"].Value.ToString();
LblSID_Data.Text = _returnedSID;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
con.Close();
clear();
ToolStripLable_Status.Text = "New Service Record Created";
}
}
The list of parameters passed through the command collection should match exactly what the stored procedure expects by name, type and direction.
Your list of parameters included in the command collection doesn't match with the parameters required by the stored procedure and thus you get the error.
At first sight I could say:
cmd.Parameters.AddWithValue("#Cname", this.TxtBx_CustomerName.Text);
cmd.Parameters.AddWithValue("#Vnum", this.TxtBx_VehicleNumber.Text);
SqlParameter ParamReturn = new SqlParameter("#SID", SqlDbType.Int);
are parameters added to the command collection but are not present in the stored procedure list of parameters.
On the contrary we have the parameters #status bit and #GrandTotal decimal(20,0) = ISNULL, required by the stored procedure but not present in the list. (By The way, the default syntax for a NULL parameter is #GrandTotal decimal(20,0) = NULL
Finally the stored procedure names a parameter #Quantity but you add a parameter named #Qty.
Now there is also the problem of the parameter types that should match otherwise you risk an automatic conversion at best or a error message stating about type mismatches.
You have numerous parameter of type int but you pass parameters of type Int16 while the correct type is Int32. And there is also a more clear error in the type of the parameter #Labor that is expected to be a decimal by the sp but you add it as an integer (16)
You have 12 parameters in the stored procedure definition (if I counted correctly), however, your code may have more or less than that. There is either one too many parameters defined within the code, or the stored procedure expects a 13th parameter. I think the error mentions the former, but I sometimes get them confused.
Anyway that error is always due to a mismatch in the number of parameters, and make sure the direction (input/output) is setup correctly, and everything is typed OK.
I am using a code to call a Stored Procedure having 2 output and 1 input parameter. But i keep getting an error every time I call this stored proc:
CREATE PROCEDURE [dbo].[usp_StoredProcName]
#inputVal nvarchar(255),
#isError bit OUTPUT,
#errorInfo nvarchar(255) OUTPUT
AS BEGIN
DECLARE #totalRow int = 0;
DECLARE #inputValID uniqueidentifier;
SET #isError = 1;
SET #errorInfo = '';
SELECT #inputValID = [inputValID]
FROM testTable
WHERE inputVal = #inputVal;
IF #inputValID IS NULL
BEGIN
SET #isError = 0;
SET #errorInfo = 'inputVal not found';
RETURN
END
END
I have used couple of C# methods to call the stored proc and I get they all return this error:
Procedure or function 'usp_StoredProcName' expects parameter '#inputVal', which was not supplied.
C# Method 1 (to call the stored proc)
using (SqlConnection con = new SqlConnection(myFullConncectionStringToDB))
{
using (SqlCommand cmd = new SqlCommand("usp_StoredProcName", con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("#inputVal", "MyParamVal_12345");
cmd.Parameters["#isError"].Direction = ParameterDirection.Output;
cmd.Parameters["#errorInfo"].Direction = ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
var isError = cmd.Parameters["#isError"].Value;
var errInfo = cmd.Parameters["#errorInfo"].Value;
con.Close();
}
}
Method 2 ( to call the stored proc)
SqlConnection con = new SqlConnection(myFullConncectionStringToDB);
SqlCommand cmd = new SqlCommand("usp_StoredProcName", con);
cmd.CommandType = CommandType.StoredProcedure;
SqlParameter in_parm = new SqlParameter("#inputVal", SqlDbType.NVarChar);
in_parm.Size = 255;
in_parm.Value = "MyParamVal_12345";
in_parm.Direction = ParameterDirection.Input;
cmd.Parameters.Add(in_parm);
SqlParameter out_parm = new SqlParameter("#errorInfo", SqlDbType.NVarChar);
out_parm.Size = 255;
out_parm.Direction = ParameterDirection.Output;
cmd.Parameters.Add(out_parm);
SqlParameter out_parm1 = new SqlParameter("#isError", SqlDbType.Bit);
out_parm1.Direction = ParameterDirection.Output;
cmd.Parameters.Add(out_parm1);
con.Open();
cmd.ExecuteNonQuery();
con.Close();
Both of the above methods I tried return the same error:
Procedure or function 'usp_StoredProcName' expects parameter '#inputVal', which was not supplied.
Please tell me what am I doing wrong here in my C# code to execute the stored procedure.
I am clearly passing the parameter value in both of my methods but can't figure out why I keep getting this error.
Thank you for your help.
I usually break down the solution into pieces an make sure each one works.
First, test the Stored Procedure to make sure it works as planned. Sample call is below.
-- Switch to your database
USE [YourDatabase]
GO
-- Declare output variables
DECLARE #out_is_error bit;
DECLARE #out_error_info nvarchar(255);
-- Execute sp
EXECUTE [dbo].[usp_StoredProcName]
N'In Data',
#isError = #out_is_error OUTPUT,
#errorInfo = #out_error_info OUTPUT;
-- Show any SQL errors / return data
PRINT ##ERROR;
PRINT 'Error = ' + #out_error_info;
PRINT 'Flag = ';
PRINT CAST(#out_is_error as CHAR(1));
GO
Next, look at the C# piece of the puzzle. Aaron suggestion about correct database is a good one. Do you have two copies of the SP floating around?
Good luck.
I have a simple package defined as follows:
CREATE OR REPLACE PACKAGE wvParty IS
TYPE refParties IS REF CURSOR;
END wvParty;
CREATE OR REPLACE PACKAGE BODY wvParty IS
PROCEDURE proc_GetParties(
p_party_name IN OUT VARCHAR2,
x_party_info OUT refParties
)
IS
BEGIN
p_party_name := '%'||p_party_name||'%';
OPEN x_party_info FOR
SELECT party_id, party_number, party_type, party_name,
person_first_name, person_middle_name, person_last_name,
known_as, known_as2, known_as3, known_as4, known_as5
FROM hz_parties
WHERE 1=1
AND party_name LIKE p_party_name;
END;
END wvParty;
It gets created in the oracle db with no errors. In my code, I'm trying to call it using:
try
{
OracleConnection conn = new OracleConnection(_connStr);
conn.Open();
OracleCommand cmd = conn.CreateCommand();
cmd.CommandText = "wvParty.proc_GetParties";
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter partyName = new OracleParameter();
partyName.ParameterName = "p_party_name";
partyName.OracleDbType = OracleDbType.Varchar2;
partyName.Direction = ParameterDirection.InputOutput;
partyName.Value = "Bubba";
cmd.Parameters.Add(partyName);
OracleParameter refParties = new OracleParameter();
refParties.ParameterName = "x_party_info";
refParties.OracleDbType = OracleDbType.RefCursor;
refParties.Direction = ParameterDirection.Output;
cmd.Parameters.Add(refParties);
OracleDataReader rdr = cmd.ExecuteReader();
Yet, when I do I get the error:
PLS-00302: component 'PROC_GETPARTIES' must be declared.
So I'm at a loss. I've created the proc as part of the package, I've declared it as I believe I should but I'm having little success resolving this. Any suggestion?
I can't comment on the C# side of things, but there are a some problems on the Oracle side, like:
proc_GetParties is defined in the package body, but is not declared in the package specification. This means that it's not visible outside the package body. This explains why you are getting the PLS-00302 error.
The 1=1 condition is not needed in the WHERE clause.
Do you really want to change the value of p_party_name within the procedure and have that change to be visible to the caller? If not, it might be better to leave p_party_name unchanged and change the LIKE condition to party_name LIKE '%' || p_party_name || '%'.
Hi I am passing an object to procedure in a oracle package using ODP.NET(C#). I am using ODP.NET because of associative arrays. I am unable to find oracledbtype.object in the ODP.NET to make parameter oracledbtype to object. which dbtype I have to use for parameter in .NET side using ODP.NET.
public Oracle.DataAccess.Client.OracleCommand oc = new Oracle.DataAccess.Client.OracleCommand();
oc.Parameters.Add("Param1", OracleDbType.Varchar2).Value = txt_RequestId.Text;
//assign the array to the parm
Oracle.DataAccess.Client.OracleParameter additionalBusiness_AssocParm = new Oracle.DataAccess.Client.OracleParameter();
// When I tried to assign parameter OracleDbType to Varchar2 it is generating an error [PLS-00306: wrong number or types of arguments in call to 'INSERT_REQUEST'].
// When I tried to change that value to Object. It is giving compliation error that object dbtype doesn't exist in Oracle.Data.Client.OracleDbType
additionalBusiness_AssocParm.OracleDbType = Oracle.DataAccess.Client.OracleDbType.Varchar2;
additionalBusiness_AssocParm.CollectionType = Oracle.DataAccess.Client.OracleCollectionType.PLSQLAssociativeArray;
additionalBusiness_AssocParm.Direction = ParameterDirection.Input;
additionalBusiness_AssocParm.Value = unitId; // unitId is an array of User defined type
oc.Parameters.Add(additionalBusiness_AssocParm);
try
{
DoQueryWithODP("TEST_PKG.INSERT_UNIT", true);
}
okay, I'll try to tackle this one without your pl/sql specification but we'll see how this works.
I will use the sample provided in the ODP installation # %ORA_HOME%\odp.net\samples\2.x\AssocArray\AssocArray.sln
as a sample talking point.
but this site is also helpful
Using PL/SQL Associative Arrays (this is actually off of a link in the article provided by mservidio, wheras that article was about ArrayBind not Associative Arrays)
CREATE TABLE TestAssociativeArray(COL1 varchar2(20), COL2 varchar2(20)) ;
/
create or replace PACKAGE MyTestAssociativeArray AS
TYPE AssocArrayVarchar2_t is table of VARCHAR(20) index by BINARY_INTEGER;
PROCEDURE TestVarchar2(Param1 IN TestAssociativeArray.COL1%type ,
Param2 IN AssocArrayVarchar2_t);
END MyTestAssociativeArray ;
/
create or replace package body MyTestAssociativeArray as
PROCEDURE TestVarchar2(Param1 IN TestAssociativeArray.COL1%type ,
Param2 IN AssocArrayVarchar2_t)
AS
i INTEGER ;
BEGIN
FOR i in Param2.first..Param2.last LOOP
insert into TestAssociativeArray(col1, col2)
values (Param1 , Param2(i)) ;
END LOOP ;
END TestVarchar2 ;
END MyTestAssociativeArray ;
/
now for the .net code:
static void Main(string[] args)
{
// Connect
string connectStr = getConnection();
// Setup the Tables for sample
OracleConnection connection = new OracleConnection(connectStr);
OracleCommand cmd = new OracleCommand("MyTestAssociativeArray.TestVarchar2", connection);
cmd.CommandType = CommandType.StoredProcedure ;
OracleParameter param1 = cmd.Parameters.Add("param1", OracleDbType.Varchar2);
OracleParameter param2 = cmd.Parameters.Add("param2", OracleDbType.Varchar2);
// Setup the direction
param1.Direction = ParameterDirection.Input;
param2.Direction = ParameterDirection.Input;
// Specify that we are binding PL/SQL Associative Array
param2.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
param1.Value = "ConstantValue" ;
param2.Value = new string[3]{"Val1",
"Val2",
"Val3"};
try
{
connection.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
Console.WriteLine(e.Message);
}
}
and the results (with cleanup)
select * from TestAssociativeArray
/
COL1 COL2
-------------------- --------------------
ConstantValue Val1
ConstantValue Val2
ConstantValue Val3
/** --clean up
drop package MyTestAssociativeArray;
drop table TestAssociativeArray ;
**/
However, since you haven't posted your spec, it may be something as simple as:
needing:
cmd.BindByName = true;
since ODP by default binds by position AND not by name (this trips up a lot of people)
This should have all the information you need. I've used this article before to perform what you're trying.
http://www.oracle.com/technetwork/issue-archive/2009/09-sep/o59odpnet-085168.html
I've modified an existing strored procedure. It originally had one ouput parameter in the stored proc and it was set up as follows in the c# code that called it:
cmd.Parameters.Add("#Var1Param", SqlDbType.BigInt);
if (Var1 == 0)
cmd.Parameters["#Var1"].Value = DBNull.Value;
else
cmd.Parameters["#Var"].Value = Var1;
cmd.Parameters["#Var1"].Direction = ParameterDirection.InputOutput;
cmd.ExecuteNonQuery();
// Get Var1
Var1= dataMorph.ToInt64(cmd.Parameters["#Var1"].Value.ToString());
Just to clarify, this parameter was declared as OUTPUT in the stored proc but as inputoutput in the C# code. This worked fine.
I have added another parameter to the same stored procedure and I want to retrieve both from the C# code. The C# code now is as follows:
SqlParameter Var1Param;
if (VAR1 == 0)
Var1Param = new SqlParameter("#Var1", DBNull.Value);
else
Var1Param = new SqlParameter("#Var1",Var1) ;
Var1Param.Direction = ParameterDirection.InputOutput ;
cmd.Parameters.Add(Var1Param);
Again this parameter is declared as output in the stored proc but inputoutput in the c# code.
Here is the new parameter. This is declared as output in the stored procedured. Here is the C# code.
SqlParameter Var2Param = new SqlParameter("#Var2", 0);
Var2Param.Direction = ParameterDirection.Output;
cmd.Parameters.Add(Var2Param);
I only want to output the second parameter as you can see. The assignment of 0 to this parameter seems to be a standard practice despite the fact it's an output variable only. I'm not sure if need to give it a type.
Now the execution
// Execute
cmd.ExecuteScalar();
connection.Close();
// Get DonationID
Var1 = dataMorph.ToInt64(cmd.Parameters["#Var1"].Value.ToString());
//Get Supersession Daf ID return param to see if new DAF was created
Var2 = dataMorph.ToInt64(cmd.Parameters["#Var2"].Value.ToString());
What happens is that both the var1 and vaf2 parameters contain the value that was assigned to #Var2 parameter in the stored procedure. I have read that any number of parameters and parameter types can be used but it seems like the value assigned to #Var2 is overwriting the Value that had been passed in or assigned to Var1.
Any advice? I know I can work around this by having multiple result sets and putting my output values in the second result set but I'd rather not deal with Kludges unless I have to. I've seen a lot of posts about the odd state of parameters after they return from stored procs and are accessed in c#. Is this type of behavior a bug?
I will point out that I'm using executenonquery because the SP does an update. sarfeast is using execute scalar. I'm assuming that this shouldn't make any difference but I'll ask if anyone has any ideas on why this is happening. I modified the code by specifying sizes for the sqlparameters and now the value for var2 is showing up in var1 and var2 is Null!!!
Any advice would be appreciated.
The following code seems to work just fine so perhaps this has something to do with the logic in your stored procedure?
CREATE PROCEDURE Outs
#var1 INT OUTPUT,
#var2 INT OUTPUT
AS
BEGIN
SELECT #var1 = 1,
#var2 = 2
END
GO
var connectionstring = #"server=rickshaw;database=becak;Trusted_Connection=true;";
using(var conn = new SqlConnection(connectionstring))
using(var cmd = new SqlCommand("Outs", conn))
{
try
{
cmd.CommandType = CommandType.StoredProcedure;
conn.Open();
cmd.Parameters.Add("#var1", SqlDbType.BigInt);
cmd.Parameters.Add("#var2", 0);
cmd.Parameters["#var1"].Value = DBNull.Value;
cmd.Parameters["#var1"].Direction = ParameterDirection.InputOutput;
cmd.Parameters["#var2"].Value = 0;
cmd.Parameters["#var2"].Direction = ParameterDirection.Output;
cmd.ExecuteScalar();
conn.Close();
var var1 = cmd.Parameters["#var1"].Value;
var var2 = cmd.Parameters["#var2"].Value;
Console.WriteLine("var1=" + var1);
Console.WriteLine("var2=" + var2);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
Console.ReadLine();