I need to use an oracle stored procedure in c#. The stored procedure is defined as followsd:
CREATE OR REPLACE PACKAGE MGRWS10.test_mp
as
type tab_assoc_array is table of varchar2(2000) index by binary_integer;
function f_loten(p_item number) return tab_assoc_array;
procedure p_loten(p_item number, o_result out tab_assoc_array);
end;
/
In c# I call the procedure:
using (var cmd = _connection.CreateCommand()){
OracleParameter stringArray = new OracleParameter();
stringArray.CollectionType = OracleCollectionType.PLSQLAssociativeArray;
stringArray.Direction = ParameterDirection.Output;
stringArray.ParameterName = "o_result";
stringArray.Size = 5;
stringArray.ArrayBindSize = new int[5];
cmd.CommandType = CommandType.StoredProcedure;
cmd.BindByName = true;
cmd.CommandText = "test_mp.p_loten(:p_item, :o_result)";
cmd.Parameters.Add("p_item", 12942);
cmd.Parameters.Add(stringArray);
_connection.Open();
await cmd.ExecuteNonQueryAsync();
var x = (string[]) stringArray.Value;
}
When executing the cmd, i get the following error:
RA-01008: not all variables bound
Try this one:
cmd.CommandType = CommandType.Text;
cmd.CommandText = "BEGIN :o_result := test_mp.p_loten(:p_item); END;";
par = cmd.Parameters.Add("o_result", OracleDbType.Varchar2, ParameterDirection.ReturnValue)
par.CollectionType = OracleCollectionType.PLSQLAssociativeArray
cmd.Parameters.Add("p_item", OracleDbType.Int32, ParameterDirection.Input).Value = 12942;
However, I never used PLSQLAssociativeArray as return value, so I don't know whether this code is working.
Maybe return a SYS_REFCURSOR instead of an PLSQLAssociativeArray, this will work for sure.
In this case your C# code may look like this:
cmd.CommandType = CommandType.Text;
cmd.CommandText = "BEGIN :o_result := test_mp.p_loten(:p_item); END;";
cmd.Parameters.Add("o_result", OracleDbType.RefCursor, ParameterDirection.ReturnValue);
cmd.Parameters.Add("p_item", OracleDbType.Int32, ParameterDirection.Input).Value = 12942;
var da = new OracleDataAdapter(cmd); // or cmd.ExecuteNonQueryAsync();
var dt = new DataTable();
da.Fill(dt);
Related
I have a stored procedure which looks like this:
PROCEDURE semifinished_lable_data(p_piece_num_id IN INTEGER,
p_piece_id OUT STRING,
p_tickness OUT NUMBER)
IS begin
select p_piece_id,p_tickness into p_piece_id,p_tickness from piece p where p.piece_num_id=p_piece_num_id;
end;
I've executed it from the database and it worked perfectly. When I execute it from c# app I don't get any value back.
Then when I researched the problem , I added that : cmd.BindByName = true
But this time i got the following error
multiple instances of named argument in list
C# codes :
OracleCommand cmd = new OracleCommand();
cmd.Connection = conn;
cmd.InitialLONGFetchSize = 1000;
var seciliProsedur = "QUA_PRINTING.semifinished_lable_data";
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = seciliProsedur;
cmd.BindByName = true;
object piece_num_id = gridViewMain.GetFocusedRowCellValue(gridViewMain.FocusedColumn);
OracleParameter PAR_ID1 = new OracleParameter();
PAR_ID1.ParameterName = "p_piece_id ";
PAR_ID1.OracleDbType = OracleDbType.Int32;
PAR_ID1.Direction = System.Data.ParameterDirection.Input;
PAR_ID1.Value =piece_num_id;
PAR_ID1.Size = 100;
cmd.Parameters.Add(PAR_ID1);
cmd.Parameters.Add("p_piece_id", OracleDbType.Varchar2, 1000, null, ParameterDirection.Output);
cmd.Parameters.Add("p_tickness", OracleDbType.Double,200, null, ParameterDirection.Output);
conn.Open();
var da = new OracleDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
How can I solve this problem ?
Actually I never used CommandType = CommandType.StoredProcedure.
Try this
cmd.CommandType = CommandType.Text;
seciliProsedur = "BEGIN QUA_PRINTING.semifinished_lable_data(:p_piece_num_id , :p_piece_id, :p_tickness); END;"
OracleParameter PAR_ID1 = new OracleParameter();
PAR_ID1.ParameterName = "p_piece_num_id";
...
cmd.Parameters.Add("p_piece_id", OracleDbType.Varchar2, ParameterDirection.Output);
cmd.Parameters("p_piece_id").DbType = DbType.Varchar2;
cmd.Parameters.Add("p_tickness", OracleDbType.Varchar2, 240, null, ParameterDirection.Output);
cmd.Parameters("p_tickness").DbType = DbType.String;
I think you must set DbType and OracleDbType property.
Then another problem of your code is
var da = new OracleDataAdapter(cmd);
var dt = new DataTable();
da.Fill(dt);
Your procedure does not return any resultSet (i.e. RefCursor), thus above commands do not work. Use
cmd.ExecuteNonQuery()
This is the output when I desc the stored procedure:
desc procedure_name
VCOMPTE VARCHAR2 IN
VRESULT REF CURSOR OUT
CLIENT_NO VARCHAR2(6) OUT
ACCT_NAME VARCHAR2(35) OUT
NCG VARCHAR2(6) OUT
NCG_DESC VARCHAR2(35) OUT
AGENCE VARCHAR2(5) OUT
TEL VARCHAR2(50) OUT
This is the C# code I am using to execute it:
public void Validate(string account_num)
{
OracleConnection conn = new OracleConnection(HelperClass.GetConstring());
OracleCommand _cmdObj = conn.CreateCommand();
_cmdObj.CommandText = "pk_xxx.procedure_name";
_cmdObj.CommandTimeout = 1680;
_cmdObj.CommandType = System.Data.CommandType.StoredProcedure;
OracleParameter para_account_num = new OracleParameter();
para_account_num.ParameterName = "VCOMPTE";
para_account_num.OracleDbType = OracleDbType.Varchar2;
para_account_num.Direction = System.Data.ParameterDirection.Input;
para_account_num.Value = account_num;
_cmdObj.Parameters.Add(para_account_num);
OracleParameter VRESULT = new OracleParameter();
VRESULT.ParameterName = "VRESULT";
VRESULT.OracleDbType = OracleDbType.RefCursor;
VRESULT.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(VRESULT);
OracleParameter client_no = new OracleParameter();
client_no.ParameterName = "CLIENT_NO";
client_no.OracleDbType = OracleDbType.Varchar2;
client_no.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(client_no);
OracleParameter acct_name = new OracleParameter();
acct_name.ParameterName = "ACCT_NAME";
acct_name.OracleDbType = OracleDbType.Varchar2;
acct_name.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(acct_name);
OracleParameter ncg = new OracleParameter();
ncg.ParameterName = "NCG";
ncg.OracleDbType = OracleDbType.Varchar2;
ncg.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(ncg);
OracleParameter tr_desc = new OracleParameter();
tr_desc.ParameterName = "NCG_DESC";
tr_desc.OracleDbType = OracleDbType.Varchar2;
tr_desc.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(tr_desc);
OracleParameter AGENCE = new OracleParameter();
AGENCE.ParameterName = "AGENCE";
AGENCE.OracleDbType = OracleDbType.Varchar2;
AGENCE.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(AGENCE);
OracleParameter TEL = new OracleParameter();
TEL.ParameterName = "TEL";
TEL.OracleDbType = OracleDbType.Varchar2;
TEL.Direction = System.Data.ParameterDirection.ReturnValue;
_cmdObj.Parameters.Add(TEL);
try
{
conn.Open();
OracleDataReader reader = _cmdObj.ExecuteReader();
while (reader.Read())
{
//I will use the data
}
}
catch (Exception xc)
{
//catch xc
}
}
But I get an error
Wrong number or types of arguments in call to "procedure_name"."
Debugging is difficult for me because I don't have direct access to the Oracle database, and I am not sure what I am doing wrong. I have successfully executed other stored procedures in the same database. Thanks in advance!
ExecuteReader() is used only for functions, not for procedures. You must use ExecuteNonQuery()
After ExecuteNonQuery() you have to read the result, e.g.
_cmdObj.ExecuteNonQuery();
OracleDataReader reader = ((OracleRefCursor)VRESULT.Value).GetDataReader();
Or create a FUNCTION like
FUNCTION function_name RETURNS SYS_REFCURSOR
VCOMPTE VARCHAR2 IN
CLIENT_NO VARCHAR2(6) OUT
ACCT_NAME VARCHAR2(35) OUT
NCG VARCHAR2(6) OUT
NCG_DESC VARCHAR2(35) OUT
AGENCE VARCHAR2(5) OUT
TEL VARCHAR2(50) OUT
And call it like this
OracleCommand _cmdObj = conn.CreateCommand();
_cmdObj.CommandText = "pk_xxx.procedure_name";
_cmdObj.CommandType = CommandType.StoredProcedure;
_cmdObj.Parameters.Add("res", OracleDbType.RefCursor, ParameterDirection.ReturnValue);
_cmdObj.Parameters.Add("VCOMPTE", OracleDbType.Varchar2, ParameterDirection.Input).Value = account_num;
_cmdObj.Parameters.Add("CLIENT_NO", OracleDbType.Varchar2, ParameterDirection.Output);
_cmdObj.Parameters.Add("ACCT_NAME", OracleDbType.Varchar2, ParameterDirection.Output);
...
OracleDataReader reader = _cmdObj.ExecuteReader();
Maybe have a look at Data Provider for .NET Developer's Guide
I have a stored procedure that accepts an input and returns multiple columns. The stored procedure works when I execute it from SSMS and also inside of VS 2013. However when I try and execute it using SqlCommand.ExecuteReader the reader doesn't have any rows in it. If I remove the output parameters from the proc and from the SqlCommand, while still keeping the one input parameter, I am able to return the row that I am looking for.
Here is the stored proc
create Proc sp_ReturnSingleGame
#GameName varchar(100) output,
#PlatformName varchar(50) output,
#ConditionShortDescription varchar(30) output,
#RetailCost decimal(6,2) output,
#InStock bit output,
#GameID int
AS
select #GameName = GameName, #PlatformName = PlatformName,
#ConditionShortDescription = ConditionShortDescription, #RetailCost = RetailCost
from Games inner join Condition
on Games.ConditionID = Condition.ConditionID
inner join ConsolePlatform
on Games.PlatformID = ConsolePlatform.PlatformID
Where Games.GameID = #GameID
if exists (select GameID
From SaleItemized
Where GameID = #GameID)
Begin
set #InStock = 1;
end
else
Begin
set #InStock = 0;
end
Here is my C# code
public Game ReturnSingleGame(int gameId)
{
SqlConnection connection = new SqlConnection(#"server=mylaptop; integrated security=true; database=GameStoreDB;");
SqlCommand command = this.ReturnCommandForSp_ReturnSingleGame(connection, gameId);
try
{
connection.Open();
SqlDataReader reader = command.ExecuteReader();
if (reader.HasRows == true)
{
reader.Read();
game.GameId = gameId;
game.GameName = reader["GameName"].ToString();
game.PlatformName = reader["PlatformName"].ToString();
game.RetailCost = (decimal) reader["RetailCost"];
}
else
{
var exception = new ApplicationException("Game was not found");
throw exception;
}
}
catch (Exception)
{
throw;
}
finally
{
connection.Close();
}
return game;
}
private SqlCommand CommandForSp_ReturnSingleGame(SqlConnection connection, int gameId)
{
string storedProc = #"dbo.sp_ReturnSingleGame";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add("#GameName", SqlDbType.VarChar, 100, "GameName");
command.Parameters["#GameName"].Direction = ParameterDirection.Output;
command.Parameters.Add("#PlatformName", SqlDbType.VarChar, 50, "PlatformName");
command.Parameters["#PlatformName"].Direction = ParameterDirection.Output;
command.Parameters.Add("#ConditionShortDescription", SqlDbType.VarChar, 30, "ConditionShortDescription");
command.Parameters["#ConditionShortDescription"].Direction = ParameterDirection.Output;
command.Parameters.Add("#RetailCost", SqlDbType.Decimal);
command.Parameters["#RetailCost"].SourceColumn = "RetailCost";
command.Parameters["#RetailCost"].Precision = 6;
command.Parameters["#RetailCost"].Scale = 2;
command.Parameters["#RetailCost"].Direction = ParameterDirection.Output;
command.Parameters.Add("#InStock", SqlDbType.Bit);
command.Parameters["#InStock"].SourceColumn = "InStock";
command.Parameters["#InStock"].Direction = ParameterDirection.Output;
command.Parameters.Add("#GameID", SqlDbType.Int).Value = gameId;
command.Parameters["#GameID"].SourceColumn = "GameID";
command.Parameters["#GameID"].Direction = ParameterDirection.Input;
command.Prepare();
return command;
}
Stored procedure provided by you actually doesn't return any rows of data.
All it does - is just set output parameters.
So you don't need any SqlDataReader to retrieve there parameters.
Just call command.ExecuteNonQuery() and then get your parameters values from command.Parameters["#GameName"].Value and so on.
Agree with Andy.
For you snippet from one of my project is:`
DbCommand Cmd = null;
using (DataClient client = new DataClient())
{
SqlParameter[] parameters = new SqlParameter[2];
parameters[0] = new SqlParameter("#ID", SqlDbType.VarChar);
parameters[0].Size = 10;
parameters[0].Direction = ParameterDirection.Output;
parameters[1] = new SqlParameter("#YourParameterName", SqlDbType.VarChar);
parameters[1].Value = Class.PropertyName;
parameters[2] = new SqlParameter("#Year", SqlDbType.Int);
client.ExecuteNonQuery("ReturnCommandForSp_ReturnSingleGame", CommandType.StoredProcedure, parameters, ref Cmd);
Then retrieve it like this
int yourReturnValue= Convert.ToInt32(Cmd.Parameters["#ID"].Value);
}
Hope it helps.
In my database I have a stored procedure with an OUTPUT parameter of type SYS_REFCURSOR. The application side is wrtitten in C#. Can I assign this procedure's output parameter to a Datatable like:
.............
OracleConnection con=new OracleConnection(......);
OracleCommand cmd=new OracleCommand("MyStoredProc",con);
cmd.CommandType=CommandType.StoredProcedure;
cmd.Parameters.Add("REC_CUR",OracleType.Cursor).Direction=ParameterDirection.Output;
con.Open();
cmd.ExecuteNonQuery();
DataTable dt=(DataTable)cmd.Parameters["REC_CUR"].value;//is this legal?
Here's the answer to my own question. If the output parametr of a stored procedure is of type SYS_REFCURSOR then the command
cmd.Parameters["REC_CUR"].value
will return an OracleDataReader object, not a table. And there's no implicit , nor explicit cast from OracledataReader to DataTable.
You can use OracleDataAdapter like below,
sample code with multiple out parameters with RefCursor :
using (OracleCommand cmd = new OracleCommand("SP1", OraCon) { CommandType = System.Data.CommandType.StoredProcedure })
{
var parm_nic = cmd.Parameters.Add("parm_nic", OracleDbType.NVarchar2);
parm_nic.Value = msgBody;
var pram_Name = cmd.Parameters.Add("pram_Name", OracleDbType.NVarchar2, 150, ParameterDirection.Output);
var pram_PAdress = cmd.Parameters.Add("pram_PAdress", OracleDbType.NVarchar2, 150, ParameterDirection.Output);
var output = cmd.Parameters.Add("pram_status", OracleDbType.RefCursor, ParameterDirection.Output);
OraCon.Open();
OracleDataAdapter ad = new OracleDataAdapter(cmd);
OracleCommandBuilder cb = new OracleCommandBuilder(ad);
DataTable dt = new DataTable();
ad.Fill(dt);
var address = pram_PAdress.Value;
var name = pram_Name.Value;
}
How do I get variable #Test that was changed in query?
const string query = #"SET #Test = 2;";
using (var connection = new SqlConnection(conStr))
{
connection.Open();
var command = new SqlCommand(query, connection);
command.Parameters.AddWithValue("#Test", 1);
var r = command.ExecuteReader();
// command.Parameters["#Test"].Value == 1
// r hasn't any variables
}
ADDED:
I've solve this problem withoute creating stored procedure
const string query = #"SET #Test = 2;";
using (var connection = new SqlConnection(conStr))
{
connection.Open();
var command = new SqlCommand(query, connection);
SqlParameter par = command.Parameters.Add("#Test", SqlDbType.NVarChar, 15);
par.Direction = ParameterDirection.Output;
command.ExecuteNonQuery();
// par.Value now contain 2
}
Both ansvers help!
Firstly, in your stored procedure the parameter needs to be marked as OUTPUT
CREATE PROC MyQuery
#Test INT OUTPUT
AS
SET #Test = 2
Then, when constructing the c# code, instead of using AddWithValue, be more explicit in your creation of a SqlParameter, namely marking it as Input/Output.
var command = new SqlCommand("MyQuery", connection);
command.CommandType = CommandType.StoredProcedure;
var param = command.CreateParameter();
param.Name = "#Test";
param.Type = DbType.Int;
param.Direction = ParameterDirection.InputOutput;
param.Value = 1;
Now once you execute your command:
command.ExecuteNonQuery(); // Could also be ExecuteReader, if you have a resultset too!
You can read the value of param, which should have changed to 2
if(param.Value == 2)
{ Console.WriteLine("WooHoo"); }