Hi guys I'm having troubles trying execute Stored procedures on cascade, I need some help. Let's see the scenario:
I have a father table, let's call it "REQUEST" and a child table, "REQUEST_DETAILS"
Now from C# I know how to execute an Oracle SP, but I donĀ“t know how to execute two in a chain, without commit until the end of all.
I need to insert the father table data and after get the generated REQUEST.ID to start to insert the children data with the REQUEST.ID
So the first stored procedure will insert the REQUEST data and the second one will insertrt the REQUEST_DETAIL data but if something goes wrong I want to rollback all the transactions.
There is a way to do this of a simple way ?
Here is my code any help will be usefull.
public Bool SaveRequest(Request newRequestData)
{
var connection = new connection();
bool isSuccess = true;
OracleConnection Conn = connection._GetInstance();
OracleCommand Cmd = new OracleCommand();
Conn.Open();
Cmd.Connection = Conn;
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.CommandText = "PackageRequests.InsertNewRequest";
Cmd.BindByName = true;
//IN PARAM
Cmd.Parameters.Add(new OracleParameter("P_LOCATION", OracleDbType.Varchar2, newRequestData.location, ParameterDirection.Input));
Cmd.Parameters.Add(new OracleParameter("P_PCSTOTAL", OracleDbType.Int32, newRequestData.pcsTotal, ParameterDirection.Input));
Cmd.Parameters.Add(new OracleParameter("P_STATUS", OracleDbType.Int32, newRequestData.status, ParameterDirection.Input));
//Out Param
Cmd.Parameters.Add(new OracleParameter("P_NEW_ID", OracleDbType.Int32)).Direction = ParameterDirection.Output;
OracleTransaction transaction = Conn.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
Cmd.ExecuteNonQuery();
//New request_id
string newId = Convert.ToString(Cmd.Parameters["P_NEW_ID"].Value);
//Here I think goes the logic for execute the another procedure that will insert the data into REQUEST_DETAIL
/***
foreach(var item in newRequestData.List)
{
//Insert request_detail_Data()
}
***/
//after all -- transaction.Commit();
}
catch (OracleException ex)
{
//If something goes wrong rollback.
transaction.Rollback();
isSuccess = false;
}
finally
{
Conn.Close();
}
return isSuccess;
}
I found the solution to do this the trick is on pass the Oracle Connection like parameter to the another functions and when all is done commit and if something fails rollback, from the initial function. I leave an example I hope will be helpful for someone.
public Bool SaveRequest(Request newRequestData)
{
var connection = new connection();
bool isSuccess = true;
OracleConnection Conn = connection._GetInstance();
OracleCommand Cmd = new OracleCommand();
Conn.Open();
Cmd.Connection = Conn;
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.CommandText = "PackageRequests.InsertNewRequest";
Cmd.BindByName = true;
// IN PARAMETERS...
Cmd.Parameters.Add(new OracleParameter("P_LOCATION", OracleDbType.Varchar2, newRequestData.location, ParameterDirection.Input));
// OUT PARAMETER (Here I recover the master table ID)
Cmd.Parameters.Add(new OracleParameter("P_NEW_ID", OracleDbType.Int32)).Direction = ParameterDirection.Output;
// Initialize the Transaction
OracleTransaction transaction = Conn.BeginTransaction(IsolationLevel.ReadCommitted);
try
{
//Execute the first SP
Cmd.ExecuteNonQuery();
string newId = Convert.ToString(Cmd.Parameters["P_NEW_ID"].Value);
// Calls another function and pass Oracle Connection, and master table ID like parameters
InsertRequestDetail(Conn, newId);
transaction.Commit();
}
catch (OracleException ex)
{
//If something goes wrong rollback.
transaction.Rollback();
isSuccess = false;
}
finally
{
Conn.Close();
}
return isSuccess;
}
private void InsertRequestDetail(OracleConnection Conn, string newId)
{
OracleCommand Cmd = new OracleCommand();
Cmd.Connection = Conn;
Cmd.CommandType = CommandType.StoredProcedure;
Cmd.CommandText = "MY_PACKAGE.AnotherSPName";
Cmd.BindByName = true;
//IN - OUT PARAMS
Cmd.Parameters.Add(new OracleParameter("...
Cmd.ExecuteNonQuery();
}
Related
I'm stuck at a loose end with inserting a new data entry into a SQL Server database. I have all the info I want to store in the following class:
public class NewSearchQuery //object reference q
{
public string Name, Location, SearchType, Path, Method;
public int RefNum;
public double Fee;
public bool Paid;
}
and after the user has filled in the form etc.. this is my code to save the info to the database:
bool complete;
string sql = $"Insert into PrivateLog (Id,Applicant,ApplicationDate,Location,Search,Paid,Method,Amount,Files) values({q.RefNum}, '{q.Name}', {AppDate}, '{q.Location}', '{q.SearchType}', {q.Paid}, '{q.Method}', {q.Fee}, '{q.Path}')";
cnn.Open();
try
{
SqlDataAdapter adapter = new SqlDataAdapter();
SqlCommand command = new SqlCommand(sql, cnn); //The Connection String cnn is in a public string variable above this method.
adapter.InsertCommand = new SqlCommand(sql, cnn);
command.Dispose();
complete = true;
}
catch (System.Exception e)
{
complete = false;
}
cnn.Close();
return complete;
Here is what my table designer looks like:
Can anyone show me why the new data entry might not be going through?
You don't need an SqlDataAdapter in that case, you can simply execute your command:
try
{
SqlCommand command = new SqlCommand(sql, cnn);
command.ExecuteNonQuery();
complete = true;
}
Although I recommend using command.Parameters to add your parameters values, protecting a possible SQL injection:
bool complete;
string sql = "Insert into PrivateLog (Id, Applicant, ApplicationDate, Location, Search, Paid, Method, Amount, Files) values(#RefNum, #Name, #AppDate, #Location, #SearchType, #Paid, #Method, #Fee, #Path)";
cnn.Open();
try
{
SqlCommand command = new SqlCommand(sql, cnn);
command.Parameters.Add("#RefNum", SqlDbType.Int).Value = q.RefNum;
command.Parameters.Add("#Name", SqlDbType.VarChar).Value = q.Name;
command.Parameters.Add("#AppDate", SqlDbType.DateTime).Value = AppDate;
command.Parameters.Add("#Location", SqlDbType.VarChar).Value = q.Location;
command.Parameters.Add("#SearchType", SqlDbType.VarChar).Value = q.SearchType;
command.Parameters.Add("#Paid", SqlDbType.Bit).Value = q.Paid;
command.Parameters.Add("#Method", SqlDbType.VarChar).Value = q.Method;
command.Parameters.Add("#Fee", SqlDbType.Decimal).Value = q.Fee;
command.Parameters.Add("#Path", SqlDbType.VarChar).Value = q.Path;
command.ExecuteNonQuery();
command.Dispose();
complete = true;
}
catch (System.Exception e)
{
complete = false;
}
cnn.Close();
return complete;
I have an update statement that works fine when I run it from SQL Developer. However, when I try to run it in C#, the program will freeze on the line that executes the command and not output anything. I have it defined as follows below:
private static OracleCommand cmd = new OracleCommand();
private static OracleConnection conn = new OracleConnection();
conn.ConnectionString = Properties.Settings.Default.myconstring;
cmd.Connection = conn;
cmd.CommandText = "UPDATE mytable SET PARAM1 = :param1 WHERE PARAM2 = :param2";
cmd.CommandType = CommandType.Text;
cmd.BindByName = true;
cmd.Parameters.Clear();
cmd.Parameters.Add(new OracleParameter(":param1", OracleDbType.Single)).Value = param1Val;
cmd.Parameters.Add(new OracleParameter(":param2", OracleDbType.Int32)).Value = param2Val;
conn.Open();
try {
cmd.ExecuteNonQuery(); //Freezes here
} catch(Exception e) {
MessageBox.Show(e.ToString());
}
conn.Close();
I have verified my values being put in are correct.
If I calling a stored proc how do i detect that it has completed succesfully on the server as right now im just doing a try catch which is not the best way of doing this.
public bool deleteTeam(Guid teamId)
{
try
{
string cs = ConfigurationManager.ConnectionStrings["uniteCms"].ConnectionString;
SqlConnection myConnection = new SqlConnection(cs.ToString());
// the stored procedure
SqlCommand cmd = new SqlCommand(
"proc_unitecms_deleteTeam", myConnection);
// 2. set the command object so it knows
// to execute a stored procedure
cmd.CommandType = CommandType.StoredProcedure;
// 3. add parameter to command, which
// will be passed to the stored procedure
cmd.Parameters.Add(
new SqlParameter("#ID", teamId));
return true;
} catch(Exception ex)
{
return false;
}
}
You can return the affected rows number and return -1 in case of catch a exception .
You forget the ExecuteNonQuery.
SqlConnection sqlConnection1 = new SqlConnection("Your Connection String");
SqlCommand cmd = new SqlCommand();
Int32 rowsAffected;
cmd.CommandText = "StoredProcedureName";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = sqlConnection1;
sqlConnection1.Open();
rowsAffected = cmd.ExecuteNonQuery();
sqlConnection1.Close();
I have procedure in my C# device application app. This is how it looks:
private void stk_crane_start_movement()
{
conn.Open();
OracleCommand cmd = new OracleCommand();
OracleTransaction trans;
trans = conn.BeginTransaction();
cmd.Transaction = trans;
cmd.Connection = conn;
conn.AutoCommit = false;
cmd.CommandTimeout = 0;
cmd.CommandText = "dc.stk_crane_start_movement";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("pn_crane_opr_id_no", OracleDbType.Number).Value = empid.ToString();
cmd.Parameters.Add("pn_crane_movement_id_no", OracleDbType.Number).Value = pn_crane_movement_id_no.ToString();
cmd.Parameters.Add(new OracleParameter("pv_error", OracleDbType.VarChar));
cmd.Parameters["pv_error"].Direction = ParameterDirection.Output;
string pv_error;
cmd.ExecuteNonQuery();
pv_error = cmd.Parameters["pv_error"].Value.ToString();
if (pv_error.ToString() == "")
{
trans.Commit();
trans.Dispose();
conn.Close();
cmd.Dispose();
}
else
{
trans.Rollback();
MessageBox.Show("" + pv_error, "Error");
}
}
I'm getting ORA-01453: SET TRANSACTION must be first statement of transaction at trans = conn.BeginTransaction();
Can someone please explain to me what exactly i'm doing wrong?
I have also tried it like this:
private void stk_crane_start_movement()
{
conn.Open();
OracleCommand cmd = conn.CreateCommand();
OracleTransaction trans;
trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Transaction = trans;
try
{
cmd.CommandText = "dc.stk_crane_start_movement";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("pn_crane_opr_id_no", OracleDbType.Number).Value = empid.ToString();
cmd.Parameters.Add("pn_crane_movement_id_no", OracleDbType.Number).Value = pn_crane_movement_id_no.ToString();
cmd.Parameters.Add(new OracleParameter("pv_error", OracleDbType.VarChar));
cmd.Parameters["pv_error"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
trans.Commit();
}
catch
{
pv_error = cmd.Parameters["pv_error"].Value.ToString();
MessageBox.Show("" + pv_error, "Error");
try
{
trans.Rollback();
}
catch (OracleException ex)
{
MessageBox.Show("Rollback failed" + ex, "Exception Error");
}
}
}
But because its not an exception error that I'm expecting it doesn't go through the try catch statement.
I want it to rollback when my pv_error variable is populated. That is why I included a if statement in the first example.
Also I don't have any other transaction before this one..
There is a suggestion here that you may see this error if you already have an open transaction. They advise committing or rolling back anything that's open. Unlike in SQL Server, I have been able to issue prophylactic "COMMIT" statements in Oracle without even knowing whether I have anything open.
The only difference I see between your code and the sample code here is that they tie the command object to the connection before assigning the transaction to it:
OracleCommand command = connection.CreateCommand();
command.Transaction = transaction;
You might want to try that variation. You're not setting an isolation level, so the issue with oracle oci.dll below version 10.2 presumably doesn't apply here.
According to the MSDN docs, your second version correctly uses the transaction. So if you combine that with your if statement, you should be fine:
private void stk_crane_start_movement()
{
conn.Open();
OracleCommand cmd = conn.CreateCommand();
OracleTransaction trans;
trans = conn.BeginTransaction(IsolationLevel.ReadCommitted);
cmd.Transaction = trans;
try
{
cmd.CommandText = "dc.stk_crane_start_movement";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("pn_crane_opr_id_no", OracleDbType.Number).Value = empid.ToString();
cmd.Parameters.Add("pn_crane_movement_id_no", OracleDbType.Number).Value = pn_crane_movement_id_no.ToString();
cmd.Parameters.Add(new OracleParameter("pv_error", OracleDbType.VarChar));
cmd.Parameters["pv_error"].Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
pv_error = cmd.Parameters["pv_error"].Value.ToString();
if (pv_error.ToString() == "")
{
trans.Commit();
trans.Dispose();
conn.Close();
cmd.Dispose();
}
else
{
trans.Rollback();
MessageBox.Show("" + pv_error, "Error");
}
i m making dll class for stored procedure as...help me to correct it...my boss said that i m missing parameter values to return but i m not getting anything to correct it...
public class transactionService
{
SqlConnection cs;
private void OpenConnection()
{
cs = new SqlConnection();
cs.ConnectionString = "Data Source=IRIS-CSG-174;Initial Catalog=library_system;Integrated Security=True";
cs.Open();
}
public membership_details calculatefine()
{
OpenConnection();
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Exec member_fine_detail";
cmd.Parameters.Add(new SqlParameter("member_id", SqlDbType.Int));
membership_details myObjec = new membership_details();
cmd.ExecuteNonQuery();
SqlDataReader sdr = cmd.ExecuteReader();
myObjec.fine_per_day = 0;
return myObjec;
help me to correct this code...i m trying to get fne_per_day as per member_id and after this reference is adding to return form in project from that according to member_id fine_per_day is calculated...as the creteria is like member_id=5,membership_desc=silver,gol,platinum,fineperday=30or 20or10
I think you will need something like this for returning the out parameter of your stored procedure:
public membership_details calculatefine()
{
OpenConnection();
SqlCommand cmd = new SqlCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "Exec member_fine_detail";
cmd.Parameters.Add(new SqlParameter("#member_id", SqlDbType.Int));
//Sql parameter corresponding to the output parameter
cmd.Parameters.Add(new SqlParameter("#fine_per_day", SqlDbType.Int));
cmd.Parameters[cmd.Parameters.Count - 1].Direction = ParameterDirection.Output;
//execute the stored procedure
cmd.ExecuteNonQuery();
//obtain the value for the output parameter
myObjec.fine_per_day = (int)cmd.Parameters["#fine_per_day"].Value;
return myObjec;
}