How do I call an Oracle function to insert data using ODP.NET and a dataset? (specific example) - oracle

We're really lost on this one, having read the ODP.NET 2 Day+ developer guide hasn't helped. I've provided the function definition (stored in a package), I don't understand what we have to cast the dataset to or what to pass the function. Here is the function definition:
FUNCTION ins (
rec_data IN OUT schema.table%ROWTYPE,
p_rowid OUT ROWID,
p_execution_ts IN schema.table.update_ts%TYPE)
RETURN NUMBER
Here is what we have done (which does nothing):
// inserts data
public void insertData(DataSet Data)
{
string connStr = "DATA SOURCE=someValidConnString";
OracleConnection conn = new OracleConnection(connStr);
string rowID = String.Empty;
Int32 rtnVal = 0;
try
{
conn.Open();
OracleCommand insCmd = new OracleCommand("PACKAGE.ins", conn);
insCmd.CommandType = CommandType.StoredProcedure;
OracleParameter outParam2 = new OracleParameter("retVal", OracleDbType.Varchar2, rtnVal,
ParameterDirection.ReturnValue);
insCmd.Parameters.Add(outParam2); //return value
OracleParameter inParam1 = new OracleParameter("rec_data", OracleDbType.NVarchar2, dsACCTData.Tables
[0].Rows[0], ParameterDirection.InputOutput);
OracleParameter outParam = new OracleParameter("p_rowid", OracleDbType.Varchar2, rowID,
ParameterDirection.Output);
OracleParameter inParam2 = new OracleParameter("p_execution_ts", OracleDbType.Date,
Oracle.DataAccess.Types.OracleDate.GetSysDate(), ParameterDirection.Input);
insCmd.Parameters.Add(inParam1); //first in out parameter
insCmd.Parameters.Add(outParam); //second out parameter
insCmd.Parameters.Add(inParam2); //third in parameter
insCmd.ExecuteNonQuery();
conn.Close();
}
catch (OracleException ee)
{
throw ee;
}
finally
{
conn.Dispose();
}
}
I know this is a vry specific question but I'm really lost. Let's assume the Oracle function ins works (it does), in this instance we simply don't know how to call it correctly using ODP.NET
Many thanks for any help.
edit: here is the error message:
ORA-06550: line 1, column 15:
PLS-00306: wrong number or types of arguments in call to 'INS'
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
Kind regards,
Fugu

maybe this could help:
http://www.c-sharpcorner.com/UploadFile/john_charles/CallingOraclestoredproceduresfromMicrosoftdotNET06222007142805PM/CallingOraclestoredproceduresfromMicrosoftdotNET.aspx
I'm looking for the same answer and I think I found something. There is example of the output variable in second row.
objCmd.Parameters.Add("pin_deptno", OracleType.Number).Value = 20;
objCmd.Parameters.Add("pout_count", OracleType.Number).Direction = ParameterDirection.Output;
Hope that link will do any good.
Regards, M

Every thing looks good. But you have to check all attribute name and attribute types.
In your example have bad data type OracleDbType.Varchar2, because your function return Number (in your Oracle Function definition)
OracleParameter outParam2 = new OracleParameter("retVal", OracleDbType.Varchar2, rtnVal,
ParameterDirection.ReturnValue);
insCmd.Parameters.Add(outParam2); //return value

Related

.net core call oracle function put returned value in first parameter

.net core 3.1
nuget: Oracle.ManagedDataAccess.Core 2.19.91
Oracle function:
create or replace NONEDITIONABLE FUNCTION GET_TOTAL_SALES
(
PARAM1 IN VARCHAR2,
PARAM2 IN VARCHAR2
)
RETURN VARCHAR2 AS
BEGIN
RETURN 'abc';
END GET_TOTAL_SALES;
.net core code:
var cmdText = "GET_TOTAL_SALES";
using (var connection = new OracleConnection(connStr))
{
using (var command = new OracleCommand(cmdText, connection))
{
connection.Open();
command.CommandType = CommandType.StoredProcedure;
var param1 = new OracleParameter("PARAM1", OracleDbType.Varchar2);
param1.Direction = ParameterDirection.Input;
param1.Value = "param1Value";
command.Parameters.Add(param1);
var param2 = new OracleParameter("PARAM2", OracleDbType.Varchar2);
param2.Direction = ParameterDirection.Input;
param2.Value = "param2Value";
command.Parameters.Add(param2);
var returnValue = new OracleParameter("returnValue", OracleDbType.Varchar2);
returnValue.Direction = ParameterDirection.ReturnValue;
command.Parameters.Add(returnValue);
command.ExecuteNonQuery();
Console.WriteLine(returnValue.Value); //""
Console.WriteLine(param1.Value); //"abc"
}
}
The result is that the returned value is putted into the first parameter (param1) and not into the returnValue. Why? Help!
I asked Oracle and got a reply:
"This is expected behavior. The first parameter bound for a function must be the return value. From the doc:
https://docs.oracle.com/en/database/oracle/oracle-data-access-components/19.3.2/odpnt/featOraCommand.html
I know, it is crazy.
We can also use binding by name:
command.BindByName = true;
and then order doesn't matter.

Cannot retrieve out parameters from oracle stored procedure using OracleManagedDataAccess

I m writing my issue here after lot of struggle and trying all the available options online.
Here is my issue. I am using ODP.Net, oracleManagedDataAccess library to connect to the oracle database.I have a stored procedure with in and out parameters which works fine when I test it from pl/sql but when I am trying to execute it from my .net code and retrieve the out parameters they return null and if I see the status of each out parameter, its false and value is "Null Fetched" and also the size of the parameter is showing up as 0, though I set the size of the parameter to 4000 for a string type. Please see my code below. Please help. As I told you earlier, my stored proc works just fine from pl/sql.
connection = new OracleConnection(DBHelper.ConnectionString);
connection.Open();
command = new OracleCommand();
command.Connection = connection;
command.CommandType = System.Data.CommandType.StoredProcedure;
command.CommandText = DBConstants.PROC_GETBORROWERSEQNO;
//Input
command.Parameters.Add("password", OracleDbType.Varchar2, 4000, password, ParameterDirection.Input);
command.Parameters.Add("userid", OracleDbType.Varchar2, 4000, userID, ParameterDirection.Input);
command.Parameters.Add("ipaddress", OracleDbType.Varchar2,4000, iPAddress, ParameterDirection.Input);
//Output
command.Parameters.Add("shawcustno", OracleDbType.Decimal).Direction = ParameterDirection.Output;
command.Parameters.Add("emailid", OracleDbType.Varchar2,4000).Direction = ParameterDirection.Output;
command.Parameters.Add("contr_phase", OracleDbType.Varchar2, 4000).Direction = ParameterDirection.Output;
command.Parameters.Add("source_seqno", OracleDbType.Decimal,15).Direction = ParameterDirection.Output;
command.Parameters.Add("borrower_seqno", OracleDbType.Decimal,15).Direction = ParameterDirection.Output;
command.Parameters.Add("pag_phone", OracleDbType.Varchar2, 4000).Direction = ParameterDirection.Output;
command.Parameters.Add("pag", OracleDbType.Varchar2, 4000).Direction = ParameterDirection.Output;
//InputOutput
command.Parameters.Add("sessionseqno", OracleDbType.Decimal).Direction = ParameterDirection.InputOutput;
sequenceNumber = command.ExecuteNonQuery();
customer = new Customer();
customer.Company = command.Parameters["company"].Value.ToString();
customer.Pag = command.Parameters["pag"].GetString();
customer.PagPhone = command.Parameters["pag_phone"].GetString();
customer.BorrowerSeqNo = command.Parameters["borrower_seqno"].IsDBNull() ? 0 : command.Parameters["borrower_seqno"].GetInt32();
customer.SourceSeqNo = command.Parameters["source_seqno"].IsDBNull() ? 0 : command.Parameters["source_seqno"].GetInt32();
customer.EmailID = command.Parameters["emailid"].GetString();
customer.ShawCustNo = command.Parameters["shawcustno"].GetString();
customer.SessionSeqNo = command.Parameters["sessionseqno"].IsDBNull() ? 0 : command.Parameters["sessionseqno"].GetInt32();
}
finally found the answer, the order of the arguments has to be exactly the same as that declared in the stored procedure. I missed that order.

Using Dapper QueryMultiple in Oracle

I´m trying to use dapper with Oracle (ODP.NET) and I would like to use the "QueryMultiple" functionality.
Passing this string to the QueryMultiple method:
var query = "Select CUST_ID CustId from Customer_info WHERE CUST_ID=:custId;" +
"Select CUST_ID CustId from BCR WHERE CUST_ID=:custId";
I´m getting a ORA-00911: invalid character error
Is there any way to do this or it´s not possible?
Tks
The OP has probably long since solved the issue by now, but as of the time of writing, this question has only one answer and it doesn't really solve the problem of using Dapper's QueryMultiple() method with Oracle. As #Kamolas81 correctly states, by using the syntax from the official examples, one will indeed get the ORA-00933: SQL command not properly ended error message. I spent a while searching for some sort of documentation about how to do QueryMultiple() with Oracle, but I was surprised that there wasn't really one place that had an answer. I would have thought this to be a fairly common task. I thought that I'd post an answer here to save me :) someone some time in the future just in case anybody happens to have this same problem.
Dapper seems to just pass the SQL command straight along to ADO.NET and whatever db provider is executing the command. In the syntax from the examples, where each command is separated by a line break, SQL server will interpret that as multiple queries to run against the database and it will run each of the queries and return the results into separate outputs. I'm not an ADO.NET expert, so I might be messing up the terminology, but the end effect is that Dapper gets the multiple query outputs and then works its magic.
Oracle, though, doesn't recognize the multiple queries; it thinks that the SQL command is malformed and returns the ORA-00933 message. The solution is to use cursors and return the output in a DynamicParameters collection. For example, whereas the SQL Server version would look like this:
var sql =
#"
select * from Customers where CustomerId = #id
select * from Orders where CustomerId = #id
select * from Returns where CustomerId = #id";
the Oracle version of the query would need to look like this:
var sql = "BEGIN OPEN :rslt1 FOR SELECT * FROM customers WHERE customerid = :id; " +
"OPEN :rslt2 FOR SELECT * FROM orders WHERE customerid = :id; " +
"OPEN :rslt3 FOR SELECT * FROM returns Where customerid = :id; " +
"END;";
For queries run against SQL Server, Dapper can handle it from there. However, because we're returning the result sets into cursor parameters, we'll need to use an IDynamicParameters collection to specify parameters for the command. To add an extra wrinkle, the normal DynamicParameters.Add() method in Dapper uses a System.Data.DbType for the optional dbType parameter, but the cursor parameters for the query need to be of type Oracle.ManagedDataAccess.Client.OracleDbType.RefCursor. To solve this, I used the solution which #Daniel Smith proposed in this answer and created a custom implementation of the IDynamicParameters interface:
using Dapper;
using Oracle.ManagedDataAccess.Client;
using System.Data;
public class OracleDynamicParameters : SqlMapper.IDynamicParameters
{
private readonly DynamicParameters dynamicParameters = new DynamicParameters();
private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction, object value = null, int? size = null)
{
OracleParameter oracleParameter;
if (size.HasValue)
{
oracleParameter = new OracleParameter(name, oracleDbType, size.Value, value, direction);
}
else
{
oracleParameter = new OracleParameter(name, oracleDbType, value, direction);
}
oracleParameters.Add(oracleParameter);
}
public void Add(string name, OracleDbType oracleDbType, ParameterDirection direction)
{
var oracleParameter = new OracleParameter(name, oracleDbType, direction);
oracleParameters.Add(oracleParameter);
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);
var oracleCommand = command as OracleCommand;
if (oracleCommand != null)
{
oracleCommand.Parameters.AddRange(oracleParameters.ToArray());
}
}
}
So all of the code together goes something like this:
using Dapper;
using Oracle.ManagedDataAccess.Client;
using System.Data;
int selectedId = 1;
var sql = "BEGIN OPEN :rslt1 FOR SELECT * FROM customers WHERE customerid = :id; " +
"OPEN :rslt2 FOR SELECT * FROM orders WHERE customerid = :id; " +
"OPEN :rslt3 FOR SELECT * FROM returns Where customerid = :id; " +
"END;";
OracleDynamicParameters dynParams = new OracleDynamicParameters();
dynParams.Add(":rslt1", OracleDbType.RefCursor, ParameterDirection.Output);
dynParams.Add(":rslt2", OracleDbType.RefCursor, ParameterDirection.Output);
dynParams.Add(":rslt3", OracleDbType.RefCursor, ParameterDirection.Output);
dynParams.Add(":id", OracleDbType.Int32, ParameterDirection.Input, selectedId);
using (IDbConnection dbConn = new OracleConnection("<conn string here>"))
{
dbConn.Open();
var multi = dbConn.QueryMultiple(sql, param: dynParams);
var customer = multi.Read<Customer>().Single();
var orders = multi.Read<Order>().ToList();
var returns = multi.Read<Return>().ToList();
...
dbConn.Close();
}
Building on greyseal96's helpful answer, I created this implementation of IDynamicParameters:
public class OracleDynamicParameters : SqlMapper.IDynamicParameters
{
private readonly DynamicParameters dynamicParameters;
private readonly List<OracleParameter> oracleParameters = new List<OracleParameter>();
public OracleDynamicParameters(params string[] refCursorNames) {
dynamicParameters = new DynamicParameters();
AddRefCursorParameters(refCursorNames);
}
public OracleDynamicParameters(object template, params string[] refCursorNames) {
dynamicParameters = new DynamicParameters(template);
AddRefCursorParameters(refCursorNames);
}
private void AddRefCursorParameters(params string[] refCursorNames)
{
foreach (string refCursorName in refCursorNames)
{
var oracleParameter = new OracleParameter(refCursorName, OracleDbType.RefCursor, ParameterDirection.Output);
oracleParameters.Add(oracleParameter);
}
}
public void AddParameters(IDbCommand command, SqlMapper.Identity identity)
{
((SqlMapper.IDynamicParameters)dynamicParameters).AddParameters(command, identity);
var oracleCommand = command as OracleCommand;
if (oracleCommand != null)
{
oracleCommand.Parameters.AddRange(oracleParameters.ToArray());
}
}
}
Assuming the same query, it can be used so:
var queryParams = new { id };
string[] refCursorNames = { "rslt1", "rslt2", "rslt3" };
var dynParams = new OracleDynamicParameters(queryParams, refCursorNames);
...
var multi = dbConn.QueryMultiple(sql, param: dynParams);
I suspect this is two or three separate things:
Your first query should not have a semi-colon
There is no new-line character between the queries
The usage notes imply that the bind character is # not : (no idea if this depends on the RDBMS being used).
If you look at the Dapper Google Code page the example given for QueryMultiple() is:
var sql =
#"
select * from Customers where CustomerId = #id
select * from Orders where CustomerId = #id
select * from Returns where CustomerId = #id";
using (var multi = connection.QueryMultiple(sql, new {id=selectedId}))
{
var customer = multi.Read<Customer>().Single();
var orders = multi.Read<Order>().ToList();
var returns = multi.Read<Return>().ToList();
...
}
Remove the semi-colon; add a new line and if you still have issues change the bind character.

DbContext stored procedures oracle 11g

I am attempting to execute a stored procedure that has several in/out parameters. This is what the expected way of doing this with SQLServer would be.
using (Context)
{
const string xml = "<test><testc>testing</testc></test>";
var userIdParam = new SqlParameter { ParameterName = "I_USER_ID", Value = user.ID };
var dtsParam = new SqlParameter { ParameterName = "I_DTS", Value = DateTime.Now };
var timeoutParam = new SqlParameter { ParameterName = "I_TIMEOUT", Value = DateTime.Now };
var xmlParam = new SqlParameter { ParameterName = "I_XML", Value = xml };
var sessionIdParam = new SqlParameter { ParameterName = "O_SESSION_ID", Value = "", Direction = ParameterDirection.Output };
var result =
Context.Database.SqlQuery<string>(
"DALLEN.SP_INSERT_SESSION I_USER_ID, I_DTS, I_TIMEOUT, I_XML, O_SESSION_ID out",
userIdParam,
dtsParam,
timeoutParam,
xmlParam,
sessionIdParam);
}
Unfortunately this does not work with oracle. I understand that ref cursors might be used in place of out parameters but that is not my own issue. Is there a good way of passing parameters to the stored procedure using dbcontext.database.sqlquery?
EDIT
Error message received when the query attempts to execute. It explains that it doesn't accept sqlParamters so I changed them to OracleParamters and that didn't work either.
"Unable to cast object of type 'System.Data.SqlClient.SqlParameter' to type 'Oracle.DataAccess.Client.OracleParameter'."
Procedure:
CREATE OR REPLACE PROCEDURE DALLEN.SP_INSERT_SESSION (
I_USER_ID IN NUMBER,
I_DTS IN DATE,
I_TIMEOUT IN DATE,
I_XML IN VARCHAR2,
O_SESSION_ID OUT NUMBER
)
AS
BEGIN
SELECT S_SESSION.NEXTVAL
INTO O_SESSION_ID
FROM DUAL;
INSERT INTO DALLEN.SYS_SESSION
(ID, USER_ID, DTS, TIMEOUT, XML)
VALUES (O_SESSION_ID, I_USER_ID, I_DTS, I_TIMEOUT, I_XML);
END;
Thank you in advance!

How to Pass datatable as input to procedure in C#?

I am wrote stored procedure to Insert data into database table but i am not getting how to pass datatable to stored procedure kindly tell how to use it.
below is my storedprocedure
CREATE OR REPLACE PROCEDURE PR_SREE_TEST(p_recordset In SYS_REFCURSOR) IS
Contrac_rc SREE_TEST%rowtype;
BEGIN
Loop
Fetch p_recordset Into Contrac_rc;
EXIT WHEN p_recordset%NOTFOUND;
Insert into SREE_TEST(CT,DESC,FLAG)
Values(Contrac_rc.CT,Contrac_rc.DESC,Contrac_rc.FLAG);
End Loop;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
-- Consider logging the error and then re-raise
RAISE;
END PR_SREE_TEST;
/
and cs page
public DataSet sreetest(DataTable dt)
{
DataSet dsRegularIndentdtl = new DataSet();
try
{
OracleConnection OraConn = new OracleConnection(strDBConnection);
OraConn.Open();
OracleCommand OraCmd = new OracleCommand();
OraCmd.Connection = OraConn;
OraCmd.CommandText = "PR_SREE_TEST";
OraCmd.CommandType = CommandType.StoredProcedure;
OracleParameter parameter = new OracleParameter();
var recordSet1 = new DataTable();
recordSet1 = dt;
OraCmd.Parameters.Add("p_recordset", OracleDbType.RefCursor, recordSet1, ParameterDirection.Input);
OraCmd.ExecuteNonQuery();
}
catch (Exception ex)
{
throw ex;
}
return dsRegularIndentdtl;
}
}
above is my code it is saying that p_recordset not valied. please tell me how to execute it.
Make sure you are using the correct overload of OraCmd.Parameters.Add(),
As per msdn the fourth parameter is not parameter direction, it is as below
public OracleParameter Add(
string parameterName,
OracleType dataType,
int size,
string srcColumn
)

Resources