In fact, you simplify casting and preparation parameters for all your procedures (procedures, functions, etc.), as well as cursor type parameters with this small automation
a) define the following type and routine in a generic package (let's 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 the C # method for calling the function above to retrieve and configure the 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); ; } } }
from). Now you can easily call any / proc function as follows. This procedure actually returns two refcursor parameters to populate the 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(); }
Here is the O.execProc2DataSet method
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 the parameters of the Proce / function without agreeing on which parameters can change from the last moment, since the parameter settings are now fully automatic. NTN