Return output parameter from C# - c#

I have a procedure with 2 input parameters and 2 output parameters. Currently its working fine. However, i want to take the two output parameters of the procedure and store it in a variable. Can anyone guide me how.
Stored procedure code:
create or replace PROCEDURE P_LOGIN_USER
(
USERNAME IN VARCHAR2
, ENCRYPTIONKEY IN VARCHAR2
, OUT_STATUS OUT VARCHAR2
, OUT_STATUS_DESC OUT VARCHAR2
)
------------------------Procedure Code
END P_LOGIN_USER
C# Code where i assign the input parameters. Missing part is getting the output parameters
OracleCommand cmd = new OracleCommand("P_LOGIN_USER", OrCon);
cmd.CommandType = CommandType.StoredProcedure;
OracleParameter in_username = new OracleParameter();
in_username.OracleDbType = OracleDbType.Varchar2;
in_username.Direction = ParameterDirection.Input;
in_username.Size = 500;
in_username.Value = username;
cmd.Parameters.Add(in_username);
OracleParameter in_ecnryptionkey = new OracleParameter();
in_ecnryptionkey.OracleDbType = OracleDbType.Varchar2;
in_ecnryptionkey.Direction = ParameterDirection.Input;
in_ecnryptionkey.Size = 500;
in_ecnryptionkey.Value = password;
cmd.Parameters.Add(in_ecnryptionkey);
OracleParameter out_1 = new OracleParameter();
out_1.OracleDbType = OracleDbType.Varchar2;
out_1.Direction = ParameterDirection.Output;
out_1.Size = 500;
cmd.Parameters.Add(out_1);
OracleParameter out_2 = new OracleParameter();
out_2.OracleDbType = OracleDbType.Varchar2;
out_2.Direction = ParameterDirection.Output;
out_2.Size = 500;
cmd.Parameters.Add(out_2);
try
{
OrCon.Open();
cmd.ExecuteNonQuery();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "P_LOGIN_USER";
cmd.Parameters.Add(new OracleParameter
{
ParameterName = "result",
Size = 1,
Direction = ParameterDirection.ReturnValue,
OracleDbType = OracleDbType.Varchar2
});
}
catch (OracleException ex)
{
Console.Write(ex.Message);
}
OrCon.Close();

You can get the value out output parameter like this.
string outputStatus = Convert.ToString(cmd.Parameters["#OUT_STATUS "].Value);
Put the above line after ExecuteNonQuery()

Stored procedure code:
create or replace PROCEDURE P_LOGIN_USER
(
USERNAME IN VARCHAR2
, ENCRYPTIONKEY IN VARCHAR2
, p_recordset OUT SYS_REFCURSOR) IS
BEGIN
OPEN p_recordset FOR
SELECT OUT_STATUS ,OUT_STATUS_DESC .....
END
C#:
using (var reader = cmd.ExecuteReader())
{
List<ListModel> obj= reader.MapToList<ListModel>();
return obj;
}
## **MapToList** ##
public static List<T> MapToList<T>(this DbDataReader dr) where T : new()
{
if (dr != null && dr.HasRows)
{
var entity = typeof(T);
var entities = new List<T>();
var propDict = new Dictionary<string, PropertyInfo>();
var props = entity.GetProperties(BindingFlags.Instance | BindingFlags.Public);
propDict = props.ToDictionary(p => p.Name.ToUpper(), p => p);
List<string> log = new List<string>();
while (dr.Read())
{
try
{
T newObject = new T();
for (int index = 0; index < dr.FieldCount; index++)
{
var columnname = dr.GetName(index).ToUpper();
if (propDict.ContainsKey(dr.GetName(index).ToUpper()))
{
var info = propDict[dr.GetName(index).ToUpper()];
if ((info != null) && info.CanWrite)
{
try
{
var val = dr.GetValue(index);
info.SetValue(newObject, (val == DBNull.Value) ? null : val, null);
}
catch (Exception ex)
{
var columename= dr.GetName(index).ToUpper();
var val= dr.GetValue(index);
var getype = val.GetType();
log.Add(columename + ":" + val + ":" + getype.ToString());
}
}
}
}
entities.Add(newObject);
}
catch (Exception ex)
{
}
}
return entities;
}
return null;
}

Related

Oracle error ORA-12571 encountered for Select Statement

I'm trying to read table data from ORACLE with Parameter binding in c#. While executing the dataAdapter I'm getting ORA-12571 exception.
Below is my code for reading multiple data at the same time.
public DataTable SelectFromServer(string qualifiedDBName, DataTable dataTable) {
try
{
if (this.Con.State == ConnectionState.Closed)
{
this.OpenConnection();
}
DataTable resultTable = new DataTable();
dataTable.TableName = qualifiedDBName;
DbProviderFactory factory = DbProviderFactories.GetFactory(this.Con);
using (DbCommand command = factory.CreateCommand())
{
command.Connection = this.Con;
command.CommandText = this.GenerateSqlToSelect(factory,command,dataTable);
DbDataAdapter adapter = factory.CreateDataAdapter();
adapter.SelectCommand = command;
adapter.Fill(resultTable);
return resultTable;
}
}
catch (Exception exc)
{
throw exc;
}
}
Below is the method where I used to generate Select Query
private string GenerateSqlToSelect(DbProviderFactory factory, DbCommand command, DataTable table)
{
//var values1 = new List<string>();
var SelectQuery = new StringBuilder();
var data = table.ToArray();
var syntax = new OracleSyntax();
command.GetType().GetProperty("ArrayBindCount").SetValue(command, table.Rows.Count, null);
for (var i = 0; i < table.Columns.Count; i++)
{
var names = new StringBuilder();
var values = new StringBuilder();
var column = table.Columns[i];
OracleParameter parameter = new OracleParameter();
parameter.ParameterName = column.ColumnName;
parameter.Direction = ParameterDirection.Input;
parameter.DbType = column.DataType.GetDbType();
parameter.Value = data[i];
parameter.ArrayBindSize = GetDataLength(data[i]);
if (SelectQuery.Length > 0)
{
SelectQuery.Append(" and ");
}
names.AppendFormat("{0}", column.ColumnName);
values.AppendFormat("{0}{1}", syntax.ParameterPrefix, column.ColumnName);
SelectQuery.AppendFormat("{0} = {1}", names, values);
command.Parameters.Add(parameter);
}
string operationString = "SELECT * FROM";
string sqlQuery = string.Format("{0} {1} WHERE {2}", operationString, this.FormatByQuote(syntax,table.TableName), SelectQuery);
return sqlQuery;
}
private int[] GetDataLength(object[] objs)
{
List<int> dataLengthIterator = new List<int>();
foreach (object obj in objs)
{
dataLengthIterator.Add(obj.ToString().Length);
}
return dataLengthIterator.ToArray();
}
this.FormatByQuote() method is nothing but getting a quoted TableName.
Output of GenerateSqlToSelect() method is
SELECT * FROM "CUSTOMER_MASTER" WHERE USER_ID= :USER_ID and LINE_NUMBER = :LINE_NUMBER
The Query is generating based upon the DataTable input
Tried multiple workarounds but could not get the reason why the exception is occurring.

Where to put the await key word in stored procedure in c#

I want to implement an async function. My problem is; I do not know where to put the await key word in the code below:
public async Task<List<ManualReadTag>> GetManuallyReadTags(ParameterManualTags model)
{
var db = new ApplicationDbContext();
using (var cnxn = db.Database.Connection)
{
cnxn.Open();
var cmd = cnxn.CreateCommand();
cmd.CommandText = "GetManualReadForDedicated";
cmd.CommandType = CommandType.StoredProcedure;
var dtFrom = cmd.CreateParameter();
dtFrom.ParameterName = "#DateFrom";
dtFrom.DbType = DbType.Date;
dtFrom.Direction = ParameterDirection.Input;
dtFrom.Value = model.DateFrom;
var dTo = cmd.CreateParameter();
dTo.ParameterName = "#DateTo";
dTo.DbType = DbType.Date;
dTo.Direction = ParameterDirection.Input;
dTo.Value = model.DateTo;
var lane = cmd.CreateParameter();
lane.ParameterName = "#Lane";
lane.DbType = DbType.Int32;
lane.Direction = ParameterDirection.Input;
lane.Value = model.Lane;
var plaza = cmd.CreateParameter();
plaza.ParameterName = "#Plaza";
plaza.DbType = DbType.String;
plaza.Direction = ParameterDirection.Input;
plaza.Value = model.Plaza;
cmd.Parameters.Add(dtFrom);
cmd.Parameters.Add(dTo);
cmd.Parameters.Add(lane);
cmd.Parameters.Add(plaza);
try
{
using (var reader = cmd.ExecuteReader())
{
var result = ((IObjectContextAdapter) db)
.ObjectContext
.Translate<ManualReadTag>(reader)
.ToList();
return result;
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
MessageBox.Show(ex.Message);
return null;
}
}
}
This code works I just need to put int the await keyword so I can use the async.
Could you please point me the right way to do this?
You can try ExecuteReaderAsync instead:
await cmd.ExecuteReaderAsync()
Everywhere where there's an asynchronous API. And don't forget to dispose of all your disposables.
public async Task<List<ManualReadTag>> GetManuallyReadTagsAsync(ParameterManualTags model)
{
var db = new ApplicationDbContext();
using (var cnxn = db.Database.Connection)
{
using (var cmd = cnxn.CreateCommand())
{
cmd.CommandText = "GetManualReadForDedicated";
cmd.CommandType = CommandType.StoredProcedure;
var dtFrom = cmd.CreateParameter();
dtFrom.ParameterName = "#DateFrom";
dtFrom.DbType = DbType.Date;
dtFrom.Direction = ParameterDirection.Input;
dtFrom.Value = model.DateFrom;
var dTo = cmd.CreateParameter();
dTo.ParameterName = "#DateTo";
dTo.DbType = DbType.Date;
dTo.Direction = ParameterDirection.Input;
dTo.Value = model.DateTo;
var lane = cmd.CreateParameter();
lane.ParameterName = "#Lane";
lane.DbType = DbType.Int32;
lane.Direction = ParameterDirection.Input;
lane.Value = model.Lane;
var plaza = cmd.CreateParameter();
plaza.ParameterName = "#Plaza";
plaza.DbType = DbType.String;
plaza.Direction = ParameterDirection.Input;
plaza.Value = model.Plaza;
cmd.Parameters.Add(dtFrom);
cmd.Parameters.Add(dTo);
cmd.Parameters.Add(lane);
cmd.Parameters.Add(plaza);
await cnxn.OpenAsync();
using (var reader = await cmd.ExecuteReaderAsync())
{
var result = ((IObjectContextAdapter)db)
.ObjectContext
.Translate<ManualReadTag>(reader)
.ToList();
return result;
}
}
}
}

Send Int parameter from C# to Stored Procedure

I have stored procedure which takes ID (INT) when I run query using DbContext.Database.SqlQuery I doesn't work. I have another Store Procedure which been script in very similar pattern except it taking all string parameter, perhaps I doing something wrong on this Int passing parameter!!!!
model class
public class DeleteFunctionNavigation_SP_Map
{
public int FunctionID { get; set; }
}
Stored Procedure
ALTER PROCEDURE [dbo].[DeleteFunctionsNavigation]
#FunctionID INT,
#Action_identity INT OUTPUT,
#ActionInFunction_Count INT OUT,
#Controller_identity INT OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT #Action_identity = Navigation_FunctionInAction.ActionID
FROM Navigation_FunctionInAction
WHERE Navigation_FunctionInAction.Function_ID = #FunctionID
..........
//my other code here!
RETURN
END
C# Class
public void DeleteNavigationFunctionByID(int _FunctionNavigationID)
{
using (var dbContext = new FunctionContext())
{
var Action_identity_out = new SqlParameter("Action_identity", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output };
var ActionInFunction_Count_out = new SqlParameter("ActionInFunction_Count", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output };
var Controller_identity_out = new SqlParameter("Controller_identity", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output };
var _query = dbContext.Database.SqlQuery<DeleteFunctionNavigation_SP_Map>("exec DeleteFunctionsNavigation #FunctionID, #Action_identity out, #ActionInFunction_Count out, Controller_identity out",
new SqlParameter("#FunctionID", SqlDbType.Int).Value = _FunctionNavigationID,
Action_identity_out,
ActionInFunction_Count_out,
Controller_identity_out
);
}
}
Controller Method
[HttpPost]
public ActionResult DeleteFunctionNavigationByID(int _selectedNavigationFunctionID)
{
try
{
_FN_Services_a2.DeleteFunctionNavigationByID(_selectedNavigationFunctionID);
}
catch (Exception ex)
{
ModelState.AddModelError("", "Unable To Delete Requested Record!" + ex);
}
return RedirectToAction("SystemCoreHome");
}
Here's how I did this. I created a function like this:
public int ExecuteNonQueryInt(string commandString, bool isStoredProc = false, params object[] param)
{
int result = 0;
try
{
using (SqlConnection con = new SqlConnection("Your connection string here"))
{
con.Open();
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandText = commandString;
cmd.CommandType = isStoredProc ? CommandType.StoredProcedure : CommandType.Text;
foreach (var parm in param)
{
cmd.Parameters.Add(parm);
}
result = cmd.ExecuteNonQuery();
}
con.Close();
}
}
catch (Exception)
{
result = 0;
}
return result;
}
Then I called it like this
SqlParameter[] sqlParameters = new SqlParameter[3]
{
new SqlParameter() { ParameterName = "keywords" , Value = dataTable, SqlDbType = SqlDbType.Structured },
new SqlParameter() { ParameterName = "moduleId" , Value = moduleId, SqlDbType = SqlDbType.UniqueIdentifier },
new SqlParameter() { ParameterName = "createdBy" , Value = createdBy, SqlDbType = SqlDbType.Int }
};
return base.ExecuteNonQueryInt("Your stored procedure", true, sqlParameters) > 0;
I have found the reason why it was not working
1) I use list of against business class
2) I was instantiating SQL parameter wrong or well it did not work for me; working model as following;
public void DeleteNavigationFunctionByID(int _FunctionNavigationID)
{
using (var dbContext = new FunctionContext())
{
List<DeleteFunctionNavigation_SP_Map> _query;
var Action_identity_out = new SqlParameter("Action_identity", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output };
var ActionInFunction_Count_out = new SqlParameter("ActionInFunction_Count", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output };
var Controller_identity_out = new SqlParameter("Controller_identity", SqlDbType.Int) { Direction = System.Data.ParameterDirection.Output };
_query = dbContext.Database.SqlQuery<DeleteFunctionNavigation_SP_Map>("exec DeleteFunctionsNavigation #FunctionID, #Action_identity out, #ActionInFunction_Count out, #Controller_identity out",
new SqlParameter("#FunctionID", _FunctionNavigationID),
Action_identity_out,
ActionInFunction_Count_out,
Controller_identity_out
).ToList();
}
}

Parameter "#xxx" has already been defined [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 10 years ago.
I have the code below and when it enters into the ForEach loop, the error hapens.
I read this
StackOverFlow
But didnt made it =\ I need to know what do I have to change. I tryed to move the MySqlCommand, but didnt solve the problem... Thanks
I had 3 different methods (Select,Insert,Update) But i had to use "Transaction" So I puted the 3 methods at the same... First time it works fine, but the second loop throught the error happens in the INSERT QUERY
#region Querys
string Select = #"SELECT id_convidado, nome, cod_dependente, dt_insercao, matricula FROM convidado_acesso WHERE debpag = 0 AND status <> 'Devolvido'";
string Insert = #"INSERT INTO debpag (
numero_int,
parcela,
tipo_pessoa,
matricula,
cod_dependente,
ev_financeiro,
quantidade,
valor_unitario,
valor_total,
dt_lancamento,
dt_vencimento,
dt_pagamento,
dt_insercao,
dt_insercao_pagamento,
referencia,
cobrador_lancto,
cobrador_pagto,
usr_lancto,
forma_pagto)
VALUES (
#numero_int,
#parcela,
#tipo_pessoa,
#matricula,
#cod_dependente,
#ev_financeiro,
#quantidade,
#valor_unitario,
#valor_total,
#dt_lancamento,
#dt_vencimento,
#dt_pagamento,
#dt_insercao,
#dt_insercao_pagamento,
#referencia,
#cobrador_lancto,
#cobrador_pagto,
#usr_lancto,
#forma_pagto)";
string Update = "UPDATE convidado_acesso SET dt_saida = #dt_saida, usr_saida= #usr_saida, status= #status, debpag = #deb WHERE nome = #nome AND debpag = 0";
#endregion
#region MySql
MySqlConnection conexao = conexao = new MySqlConnection("Server= localhost; Database = crdores; Uid= root;Pwd = ik9rru2j;Allow Zero Datetime = true");
MySqlCommand cmd = new MySqlCommand();
cmd.Connection = conexao;
cmd.CommandType = CommandType.Text;
cmd.CommandText = Select;
MySqlDataAdapter da = new MySqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
conexao.Open();
ta = conexao.BeginTransaction();
#endregion
try
{
#region TratamentoSelect
List<Convidado> convidado = null;
Convidado retorno = null;
if ((ds.Tables.Count > 0) && (ds.Tables[0].Rows.Count > 0))
{
convidado = new List<Convidado>();
foreach (DataRow row in ds.Tables[0].Rows)
{
string status = "";
int deb = 0;
retorno = new Convidado();
try
{
retorno.Nome = row["nome"].ToString();
}
catch { }
try
{
retorno.Cod_Dep = Convert.ToInt32(row["cod_dependente"]);
}
catch { }
try
{
retorno.Dt_Insercao = Convert.ToDateTime(row["dt_insercao"]);
}
catch { }
try
{
retorno.Matricula = Convert.ToInt32(row["matricula"]);
}
catch { }
try
{
retorno.Id_Convidado = Convert.ToInt32(row["id_convidado"]);
}
catch { }
#region Variaveis
string tmp = BuscaTempoLimite();
int z = tmp.Length;
string h = tmp.Remove(1, z - 1);
string m = tmp.Remove(0, 2);
string saida = BuscaHoraServidor();
retorno.Dt_Insercao = retorno.Dt_Insercao.AddMinutes(15);
string entrada = retorno.Dt_Insercao.ToString("HH:mm");
DateTime insercao = Convert.ToDateTime(retorno.Dt_Insercao);
DateTime left = Convert.ToDateTime(saida);
saida = left.ToString("HH:mm");
int horaEntrada = Convert.ToInt32(entrada.Remove(2, 3));
int minutosEntrada = Convert.ToInt32(entrada.Remove(0, 3));
int horaSaida = Convert.ToInt32(saida.Remove(2, 3));
int minutosSaida = Convert.ToInt32(saida.Remove(0, 3));
TimeSpan first = new TimeSpan(horaEntrada, minutosEntrada, 0);
TimeSpan last = new TimeSpan(horaSaida, minutosSaida, 0);
TimeSpan result = last - first;
TimeSpan limite = new TimeSpan(Convert.ToInt32(h), Convert.ToInt32(m), 59);
int hora = last.Hours - first.Hours;
int minutosss = last.Minutes - first.Minutes;
result = new TimeSpan(hora, minutosss, 0);
#endregion
if (left.Day <= insercao.Day)
{
if (result > limite)
{
status = "Pago";
deb = 0;
}
else
{
status = "Devolvido";
deb = 2;
}
}
else
{
status = "Pago";
}
#endregion
#region TratamentoInsert
cmd.CommandText = Insert;
#region váriaveis
int cash = 0;
string eventoF = "", usre = "", cobrador = "", tmpLimite = "";
int ide = 0;
ide = PegaMaxID();
string insercao_pagto;
string dt_lancamento = BuscaHoraServidor();
string saidaa = VerificaSaida(Convert.ToInt32(retorno.Id_Convidado));
string referencia = retorno.Dt_Insercao.ToString("MM/yyyy");
if (saida != "")
{
insercao_pagto = saida;
}
else
{
insercao_pagto = BuscaHoraServidor();
}
int tipo_pessoa;
if (retorno.Cod_Dep > 0)
{
tipo_pessoa = 3;
}
else
{
tipo_pessoa = 1;
}
retorno.Dt_Insercao = retorno.Dt_Insercao.AddHours(1);
retorno.Dt_Insercao = retorno.Dt_Insercao.AddMinutes(15);
retorno.Dt_Insercao = retorno.Dt_Insercao.AddSeconds(59);
string ent = retorno.Dt_Insercao.ToString("dd/MM/yyyy");
#endregion
DataSet confg = pag.BuscaConfigs();
foreach (DataRow roww in confg.Tables[0].Rows)
{
eventoF = roww["ev_financeiro"].ToString();
cash = Convert.ToInt32(roww["valor"]);
usre = roww["usr_insercao"].ToString();
tmpLimite = roww["tempo_permanencia"].ToString();
cobrador = roww["cod_cobrador"].ToString();
}
cmd.Parameters.Add(new MySqlParameter("#numero_int", MySqlDbType.Int32)).Value = ide + 1; **//HERE THE ERROR STARTS**
cmd.Parameters.Add(new MySqlParameter("#parcela", MySqlDbType.VarChar)).Value = "1/1";
cmd.Parameters.Add(new MySqlParameter("#tipo_pessoa", MySqlDbType.Int32)).Value = tipo_pessoa;
cmd.Parameters.Add(new MySqlParameter("#matricula", MySqlDbType.Int32)).Value = retorno.Matricula;
cmd.Parameters.Add(new MySqlParameter("#cod_dependente", MySqlDbType.Int32)).Value = retorno.Cod_Dep;
cmd.Parameters.Add(new MySqlParameter("#ev_financeiro", MySqlDbType.Int32)).Value = eventoF;
cmd.Parameters.Add(new MySqlParameter("#quantidade", MySqlDbType.Int32)).Value = 1;
cmd.Parameters.Add(new MySqlParameter("#valor_unitario", MySqlDbType.Double)).Value = Convert.ToDouble(cash);
cmd.Parameters.Add(new MySqlParameter("#valor_total", MySqlDbType.Double)).Value = Convert.ToDouble(cash);
cmd.Parameters.Add(new MySqlParameter("#dt_lancamento", MySqlDbType.Date)).Value = Convert.ToDateTime(dt_lancamento); // X
cmd.Parameters.Add(new MySqlParameter("#dt_vencimento", MySqlDbType.Date)).Value = ent; // X
cmd.Parameters.Add(new MySqlParameter("#dt_pagamento", MySqlDbType.Date)).Value = saida; // X
cmd.Parameters.Add(new MySqlParameter("#dt_insercao", MySqlDbType.DateTime)).Value = saida; // X
cmd.Parameters.Add(new MySqlParameter("#dt_insercao_pagamento", MySqlDbType.DateTime)).Value = insercao_pagto; // X
cmd.Parameters.Add(new MySqlParameter("#referencia", MySqlDbType.Date)).Value = referencia;
cmd.Parameters.Add(new MySqlParameter("#cobrador_lancto", MySqlDbType.VarChar)).Value = cobrador;
cmd.Parameters.Add(new MySqlParameter("#cobrador_pagto", MySqlDbType.VarChar)).Value = cobrador;
cmd.Parameters.Add(new MySqlParameter("#usr_lancto", MySqlDbType.VarChar)).Value = usre;
cmd.Parameters.Add(new MySqlParameter("#forma_pagto", MySqlDbType.Int32)).Value = 1;
cmd.ExecuteNonQuery();
#endregion
#region TratamentoUpdate
cmd.CommandText = Update;
cmd.Parameters.Add(new MySqlParameter("#dt_saida", MySqlDbType.DateTime)).Value = conv.Dt_Saida;
cmd.Parameters.Add(new MySqlParameter("#usr_saida", MySqlDbType.VarChar)).Value = usuario;
cmd.Parameters.Add(new MySqlParameter("#status", MySqlDbType.VarChar)).Value = status;
cmd.Parameters.Add(new MySqlParameter("#deb", MySqlDbType.Int32)).Value = deb;
cmd.Parameters.Add(new MySqlParameter("#nome", MySqlDbType.VarChar)).Value = retorno.Nome;
cmd.ExecuteNonQuery();
#endregion
ta.Commit();
}
}
}
Cmd.Parameter.Clear() Is not a good practise. Here's the ANSWER.
Outside the ForEachLoop :
Cmd.Parameter.Add(new MySqlParameter("#Hellow", MySqlDataType));
Inside the ForEachLoop
Cmd.Parameter["#Hellow"].Value = anyValueOrVariable;
You're adding the same parameters to your command over and over again in the loop. The exception is telling you the problem.
Either store your parameters outside the loop and reset the values or clear the parameters each time through the loop.
The quickest solution would be something like this:
#region TratamentoInsert
cmd.Parameters.Clear();//<--clear all the parameters.
cmd.CommandText = Insert;
Not sure if that's the exact code to clear the parameters collection or not but I'm late for a flight and can't check. It'll be something like that.
You are adding parameters to cmd on every loop. Create the parameters at the same point you initialize cmd, or clear them before adding again.

Calling Oracle function that returns type from C#

I am using c# to try and call a function in an Oracle package that returns a Type.
I've spent the last couple of days researching this, so far the advice i've come across is:
to use the odp.net 11g Data Access driver.
ensure the parameter output direction is set to returnvalue
ensure the parameter output is first parameter added
Give the output parameter a udttypename which is the Oracle type
name.
To make sure this udttypename is Upper Case (A few similar cases asked on her were resolved by this)
Below is the Oracle package (package is called prefs):
Type P_Details Is Record(
var1 a.a_Type_Key%Type
,var2 Varchar2(1)
,var3 a.b%Type
,var4 c.Type_Key%Type
,var5 d.Code%Type
,var6 d.Product_Path%Type
,var7 a.Channel_Key%Type
,var8 a.From_Date%Type
,var9 a.To_Date%Type);
Type P_List Is Table Details;
Function Get(p_1 In Number,
p_2 In Varchar2,
p_3 In Varchar2,
p_4 In Date,
p_5 In Out Varchar2) Return List;
Below is the C# code used for calling the Oracle package.
using (var connection = new OracleConnection(ConnectionString))
{
using (var command = new OracleCommand
{
CommandType = CommandType.StoredProcedure,
CommandText = "PACKAGENAME.FUNCTIONNAME",
Connection = connection,
BindByName = true
})
{
var output = new OracleParameter
{
UdtTypeName = "PREFS.PREFERENCE_LIST",
ParameterName = "p_details",
OracleDbType = OracleDbType.Object,
Direction = ParameterDirection.ReturnValue
};
command.Parameters.Add(output);
command.Parameters.Add(new OracleParameter
{
ParameterName = "p_1",
OracleDbType = OracleDbType.Decimal,
Direction = ParameterDirection.Input,
Value = details.RuleId
});
command.Parameters.Add(new OracleParameter
{
ParameterName = "p_2",
OracleDbType = OracleDbType.Decimal,
Direction = ParameterDirection.Input,
Value = details.CustomerDetails.CtiId
});
command.Parameters.Add(new OracleParameter
{
ParameterName = "p_3",
OracleDbType = OracleDbType.Varchar2,
Direction = ParameterDirection.Input,
Value = details.CustomerDetails.Surname
});
command.Parameters.Add(new OracleParameter
{
ParameterName = "p_4",
OracleDbType = OracleDbType.Varchar2,
Direction = ParameterDirection.Input,
Value = details.CustomerDetails.Postcode
});
command.Parameters.Add(new OracleParameter
{
ParameterName = "p_5",
OracleDbType = OracleDbType.Date,
Direction = ParameterDirection.Input,
Value = details.CustomerDetails.DateOfBirth
});
command.Parameters.Add(new OracleParameter
{
ParameterName = "p_6",
OracleDbType = OracleDbType.Varchar2,
Direction = ParameterDirection.InputOutput
});
connection.Open();
command.ExecuteNonQuery();
}
}
I'm now getting an error
"OCI-22303: type "PACKAGENAME.TYPENAME" not found"
For the UDTTYPENAME i've tried the following formats
TYPENAME
FUNCTIONNAME.TYPENAME
PACKAGENAME.TYPENAME
PACKAGENAME.TYPENAME
PACKAGENAME.FUNCTIONNAME.TYPENAME
SCHEMA.PACKAGENAME.TYPENAME
I'd appreciate any help and response for this as i've now run out of ideas.
You can actually simplify the casting and preparing parameters for all your Routines(Procedures,functions etc.) and also parameters of ref cursor type with this little automation
a) define a following type and routine in a common package (lets call it utils).
Type recRoutineSchema is Record (ColumnName varchar2(64),DataType Varchar2(20), ColumnOrder number, Direction varchar2(10), sSize nUMBER);
Type tblRoutineSchema is table of recRoutineSchema;
function ftRoutineSchema(pkg varchar2,Routine varchar2) return tblRoutineSchema PIPELINED is
x recRoutineSchema;
pkN varchar2(100);
rtN varchar2(100);
Begin
FOR Y in ( Select Argument_Name ColumnName
,Data_type DataType
,Position ColumnOrder
,In_out Direction
,Data_length SSize
from user_ARGUMENTS
where package_Name=Upper(pkg)
and object_name=Upper(Routine) order by position
)
LOOP
PIPE ROW(Y);
END LOOP;
Return;
End;
b) and a c# method to call above function to retrieve and setup parameters of the procedure/function you are calling
public void SetupParams(string RoutineName, OracleCommand cmd, IDictionary<string, string> prms, bool keepConnectionOpen = true)
{
Debug.WriteLine("Setting parameters for " + RoutineName);
if (cmd != null) cmd.Parameters.Clear();
string pname = "";
string[] s = RoutineName.Split('.');
DataTable tblParams = Select(String.Format("Select * from Table(pkgUtils.ftRoutineSchema('{0}','{1}')) ", s[0], s[1]));
cmd.CommandText=RoutineName;
foreach (DataRow dr in tblParams.Rows)
{
using (OracleParameter p = new OracleParameter())
{
pname = dr["COLUMnNAME"].ToString() == "" ? "returnvalue" : pname = dr["COLUMnNAME"].ToString().ToLower();
if (prms.Keys.Contains(pname)) p.Value = prms[pname];
string direction = dr["Direction"].ToString().ToLower();
string sptype = (string)dr["DataType"];
string[] sx = dr["DataType"].ToString().Split(new char[] { '(', ',', ')' });
direction = pname == "returnvalue" ? "rc" : direction;
p.ParameterName = pname;
#region case type switch
switch (sx[0].ToLower())
{
case "number":
// p.DbType = OracleDbType.Decimal;
p.OracleDbType = OracleDbType.Decimal;
break;
case "varchar2":
p.DbType = DbType.String;
p.Size = 65536;
// p.Size = prms[pname].Length;
// p.Size = int.Parse(sx[1]);
break;
case "ref cursor":
p.OracleDbType = OracleDbType.RefCursor;
// direction = "rc"; // force return value
break;
case "datetime":
p.DbType = DbType.DateTime;
break;
case "ntext":
case "text":
p.DbType = DbType.String;
p.Size = 65536;
break;
default:
break;
}
//-------------------------------------------------------------------------------
switch (direction)
{
case "in": p.Direction = ParameterDirection.Input; break;
case "out": p.Direction = ParameterDirection.Output; break;
case "in/out": p.Direction = ParameterDirection.InputOutput; break;
case "rc": p.Direction = ParameterDirection.ReturnValue; break;
default: break;
}
#endregion
cmd.Parameters.Add(p); ;
}
}
}
c). now you can easily call any function/proc as follows this procedure actually returns two out refcursor parameters to poplulate a dataset.
private void btnDumpExcel_Click(object sender, EventArgs e)
{
IDictionary<string, string> p = new Dictionary<string, string>();
p.Add("pcomno", "020");
p.Add("pcpls", "221");
p.Add("pUploaderName", "Anthony Peiris");
try
{
pGroupDs = O.execProc2DatSet("priceWorx.prSnapshotDiscounts", p, false, false);
Excel.MakeWorkBook(ref pGroupDs, ref O, "1");
}
catch (Exception ex)
{
Debug.WriteLine(ex);
Debugger.Break();
}
//Excel.MakeWorkBook(ref ds, ref O, "1");
}
Here is the method O.execProc2DataSet
public DataSet execProc2DatSet(string storedProcedureName, IDictionary<string, string> prms, bool propagateDbInfo, bool leaveConnectionOpen = false)
{
// initPackage(storedProcedureName.Substring(0,storedProcedureName.IndexOf('.')));
try
{
using (OracleCommand cmd = new OracleCommand("", conn))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = storedProcedureName;
//dep = new OracleDependency(cmd);
//dep.OnChange += new OnChangeEventHandler(dep_OnChange);
if (prms != null) SetupParams(storedProcedureName, cmd, prms, true);
using (OracleDataAdapter da = new OracleDataAdapter(cmd))
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
cmd.Connection = conn;
}
using (DataSet ds = new DataSet())
{
da.Fill(ds);
return ds;
}
}
}
}
catch (Exception ex)
{
Debug.WriteLine(ex);
Debugger.Break();
return null;
}
finally
{
if (!leaveConnectionOpen) conn.Close();
}
}
This approach allows you to change your Proce/function parameters without being concerend about what parameters may have changed since last, since the parameter setup is now fully automatic.
HTH

Categories