I am trying to run this code
public Exception SetData(string Data , long NoOfColumnsAllowed)
{
try
{
con = new SqlCeConnection(conectionstring);
con.Open();
transaction = con.BeginTransaction();
com = new SqlCeCommand();
com.Transaction = transaction;
com.CommandText = "Select count(*) from [Copy]";
com.Connection = con;
sdr = com.ExecuteReader();
while (sdr.Read())
{
noOfColumns = sdr.GetInt32(0);
}
if (noOfColumns > NoOfColumnsAllowed)
{
long NoOfColumsToBeDeleted = noOfColumns - NoOfColumnsAllowed;
com.CommandText = "delete from [Copy] where Sno<=#sno";
com.Parameters.AddWithValue("#sno", NoOfColumsToBeDeleted);
com.ExecuteNonQuery();
}
com.CommandText = "Insert into [Copy] (Data) values (#data)";
com.Parameters.AddWithValue("#data", Data);
com.ExecuteNonQuery();
transaction.Commit();
con.Close();
return null;
}
catch (Exception ex)
{
try
{
transaction.Rollback();
}
catch (Exception)
{
}
con.Close();
return ex;
}
}
Exception Occur -
system.invalidoperationexception : The transaction can not be
committed if there is any opened cursor in the scope of this
transaction . Make sure all the data readers/ result sets are
explicitly closed before committing the change .
I am new with transaction and not able to find any valuable solution about opened cursor. Is there something wrong with code or i have to explicitly close the data reader if yes please tell me how ?
Just call sdr.Close(); right after the while loop since that's what error is complaining about.
Related
I have a Data-table with all the mandatory fields which is required by select query in it. Now i am fetching data from 1st row of the data-table and running a select query (as given below). For the first time its working fine.
Now I am taking the 2nd row and giving all the mandatory fields (as i did for the first) and running the select query its giving error "insufficient permissions". When i am running both the select query (which are actually same but with different parameter) manually in Oracle SQL Developer its working fine.
Query1: select cloumnname1 from table where columnname2='valueA' and columnname3= 'VALUEB'
Query2: select cloumnname1 from table where columnname2='valueA' and columnname3= 'VALUEB'
To fetch data from database
public OracleDataReader ExecuteReader(string SelectQuery, string conString)
{
try
{
OpenDbConnection(conString);
OracleCommand cmd = new OracleCommand();
cmd.Connection = con;
cmd.CommandText = SelectQuery;
cmd.CommandType = System.Data.CommandType.Text;
OracleDataReader ora_dataReader = cmd.ExecuteReader();
return ora_dataReader;
}
catch (Exception ex)
{
throw ex;
}
finally
{
}
}
EDIT:
Forgot to mention that i am calling this funtion in another function as given below
public DataTable GetDataFromDB(string SelectQuery, string conString)
{
try
{
DataTable dt = new DataTable();
dt.Load(ExecuteReader(SelectQuery,conString));
return dt;
}
catch (Exception ex)
{
throw ex;
}
finally
{
CloseDbConnection();
}
}
You need to open and close the connection after each query execution.
And also return the OracleDataReader after you have closed the connection or else it would lead to memory leak. If you return the OracleDataReader before you close connection, you would get the same error.
Try something like this:
public OracleDataReader ExecuteReader(string SelectQuery, string conString)
{
try
{
OpenDbConnection(conString);
OracleCommand cmd = new OracleCommand();
con.Open();
cmd.Connection = con;
cmd.CommandText = SelectQuery;
cmd.CommandType = System.Data.CommandType.Text;
OracleDataReader ora_dataReader = cmd.ExecuteReader();
}
catch (Exception ex)
{
Logging.LogMessage(Logging.LogLevel.Error, 0, "DAL", this.GetType().Name, ex.Message + " : " + ex.StackTrace);
throw ex;
}
finally
{
con.close();
con.Dispose();
}
return ora_dataReader;
}
More info in this reference: https://msdn.microsoft.com/en-us/library/system.data.oracleclient.oracledatareader(v=vs.110).aspx
You need to close the database connection and open it again before firing up your second query.
something like:
SqlConnection.Open();
And
SqlConnection.Close();
You need to ensure you're closing both the Connection and DataReader objects.
Try using the CommandBehavior argument in ExecuteReader, as it will close the connection automatically once you close the DataReader.
cmd.ExecuteReader(CommandBehavior.CloseConnection)
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 am receiving this error message when i try to execute the following code.
ExecuteNonQuery requires the command to have a transaction when the connection assigned to the command is in a pending local transaction
Can anyone advice where the problem is? I guess the root of the problem is the part where i try to execute a stored procedure.
The stored procedure is creates its own transaction when execute
using (SqlConnection conn = new SqlConnection(connStr))
{
conn.Open();
SqlCommand command = conn.CreateCommand();
SqlTransaction transaction;
// Start a local transaction.
transaction = conn.BeginTransaction("createOrder");
// Must assign both transaction object and connection
// to Command object for a pending local transaction
command.Connection = conn;
command.Transaction = transaction;
try
{
command.CommandText = "INSERT INTO rand_resupply_order (study_id, centre_id, date_created, created_by) " +
"VALUES (#study_id, #centre_id, #date_created, #created_by) SET #order_id = SCOPE_IDENTITY()";
command.Parameters.Add("#study_id", SqlDbType.Int).Value = study_id;
command.Parameters.Add("#centre_id", SqlDbType.Int).Value = centre_id;
command.Parameters.Add("#date_created", SqlDbType.DateTime).Value = DateTime.Now;
command.Parameters.Add("#created_by", SqlDbType.VarChar).Value = username;
SqlParameter order_id = new SqlParameter("#order_id", SqlDbType.Int);
//study_name.Value =
order_id.Direction = ParameterDirection.Output;
command.Parameters.Add(order_id);
command.ExecuteNonQuery();
command.Parameters.Clear();
//loop resupply list
for (int i = 0; i < resupplyList.Count(); i++)
{
try
{
SqlCommand cmd = new SqlCommand("CreateOrder", conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("#study_id", SqlDbType.Int).Value = study_id;
cmd.Parameters.Add("#centre_id", SqlDbType.Int).Value = centre_id;
cmd.Parameters.Add("#created_by", SqlDbType.VarChar).Value = username;
cmd.Parameters.Add("#quantity", SqlDbType.VarChar).Value = resupplyList[i].Quantity;
cmd.Parameters.Add("#centre_id", SqlDbType.Int).Value = centre_id;
cmd.Parameters.Add("#depot_id", SqlDbType.VarChar).Value = depot_id;
cmd.Parameters.Add("#treatment_code", SqlDbType.Int).Value = centre_id;
cmd.Parameters.Add("#order_id", SqlDbType.Int).Value = (int)order_id.Value;
cmd.ExecuteNonQuery();
}
catch (SqlException ex)
{
transaction.Rollback();
ExceptionUtility.LogException(ex, "error");
throw ex;
}
catch (Exception ex)
{
transaction.Rollback();
ExceptionUtility.LogException(ex, "error");
throw ex;
}
finally
{
conn.Close();
conn.Dispose();
}
}
return (int)order_id.Value;
}
catch (Exception ex)
{
transaction.Rollback();
ExceptionUtility.LogException(ex, "error");
throw ex;
}
finally
{
// Attempt to commit the transaction.
transaction.Commit();
conn.Close();
conn.Dispose();
command.Dispose();
}
when using transaction, you should use it everywhere.
cmd.Transaction = transaction;
using Connection String transaction not popular so far.you can delete every things that related to SqlTransaction and then wrap your code with TransactionScope
First question:
Say I have
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
Does the connection get closed? Because technically we never get to the last } as we return before it.
Second question:
This time I have:
try
{
using (SqlConnection connection = new SqlConnection(connectionString))
{
int employeeID = findEmployeeID();
connection.Open();
SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
}
catch (Exception) { /*Handle error*/ }
Now, say somewhere in the try we get an error and it gets caught. Does the connection still get closed? Because again, we skip the rest of the code in the try and go directly to the catch statement.
Am I thinking too linearly in how using works? ie Does Dispose() simply get called when we leave the using scope?
Yes
Yes.
Either way, when the using block is exited (either by successful completion or by error) it is closed.
Although I think it would be better to organize like this because it's a lot easier to see what is going to happen, even for the new maintenance programmer who will support it later:
using (SqlConnection connection = new SqlConnection(connectionString))
{
int employeeID = findEmployeeID();
try
{
connection.Open();
SqlCommand command = new SqlCommand("UpdateEmployeeTable", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
catch (Exception)
{
/*Handle error*/
}
}
Yes to both questions. The using statement gets compiled into a try/finally block
using (SqlConnection connection = new SqlConnection(connectionString))
{
}
is the same as
SqlConnection connection = null;
try
{
connection = new SqlConnection(connectionString);
}
finally
{
if(connection != null)
((IDisposable)connection).Dispose();
}
Edit: Fixing the cast to Disposable
http://msdn.microsoft.com/en-us/library/yh598w02.aspx
Here is my Template. Everything you need to select data from an SQL server. Connection is closed and disposed and errors in connection and execution are caught.
string connString = System.Configuration.ConfigurationManager.ConnectionStrings["CompanyServer"].ConnectionString;
string selectStatement = #"
SELECT TOP 1 Person
FROM CorporateOffice
WHERE HeadUpAss = 1 AND Title LIKE 'C-Level%'
ORDER BY IntelligenceQuotient DESC
";
using (SqlConnection conn = new SqlConnection(connString))
{
using (SqlCommand comm = new SqlCommand(selectStatement, conn))
{
try
{
conn.Open();
using (SqlDataReader dr = comm.ExecuteReader())
{
if (dr.HasRows)
{
while (dr.Read())
{
Console.WriteLine(dr["Person"].ToString());
}
}
else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
}
}
catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
if (conn.State == System.Data.ConnectionState.Open) conn.Close();
}
}
* Revised: 2015-11-09 *
As suggested by NickG; If too many braces are annoying you, format like this...
using (SqlConnection conn = new SqlConnection(connString))
using (SqlCommand comm = new SqlCommand(selectStatement, conn))
{
try
{
conn.Open();
using (SqlDataReader dr = comm.ExecuteReader())
if (dr.HasRows)
while (dr.Read()) Console.WriteLine(dr["Person"].ToString());
else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)");
}
catch (Exception e) { Console.WriteLine("Error: " + e.Message); }
if (conn.State == System.Data.ConnectionState.Open) conn.Close();
}
Then again, if you work for EA or DayBreak games, you can just forgo any line-breaks as well because those are just for people who have to come back and look at your code later and who really cares? Am I right? I mean 1 line instead of 23 means I'm a better programmer, right?
using (SqlConnection conn = new SqlConnection(connString)) using (SqlCommand comm = new SqlCommand(selectStatement, conn)) { try { conn.Open(); using (SqlDataReader dr = comm.ExecuteReader()) if (dr.HasRows) while (dr.Read()) Console.WriteLine(dr["Person"].ToString()); else Console.WriteLine("No C-Level with Head Up Ass Found!? (Very Odd)"); } catch (Exception e) { Console.WriteLine("Error: " + e.Message); } if (conn.State == System.Data.ConnectionState.Open) conn.Close(); }
Phew... OK. I got that out of my system and am done amusing myself for a while. Carry on.
Dispose simply gets called when you leave the scope of using. The intention of "using" is to give developers a guaranteed way to make sure that resources get disposed.
From MSDN:
A using statement can be exited either when the end of the using statement is reached or if an exception is thrown and control leaves the statement block before the end of the statement.
Using generates a try / finally around the object being allocated and calls Dispose() for you.
It saves you the hassle of manually creating the try / finally block and calling Dispose()
In your first example, the C# compiler will actually translate the using statement to the following:
SqlConnection connection = new SqlConnection(connectionString));
try
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
finally
{
connection.Dispose();
}
Finally statements will always get called before a function returns and so the connection will be always closed/disposed.
So, in your second example the code will be compiled to the following:
try
{
try
{
connection.Open();
string storedProc = "GetData";
SqlCommand command = new SqlCommand(storedProc, connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#EmployeeID", employeeID));
return (byte[])command.ExecuteScalar();
}
finally
{
connection.Dispose();
}
}
catch (Exception)
{
}
The exception will be caught in the finally statement and the connection closed. The exception will not be seen by the outer catch clause.
I wrote two using statements inside a try/catch block and I could see the exception was being caught the same way if it's placed within the inner using statement just as ShaneLS example.
try
{
using (var con = new SqlConnection(#"Data Source=..."))
{
var cad = "INSERT INTO table VALUES (#r1,#r2,#r3)";
using (var insertCommand = new SqlCommand(cad, con))
{
insertCommand.Parameters.AddWithValue("#r1", atxt);
insertCommand.Parameters.AddWithValue("#r2", btxt);
insertCommand.Parameters.AddWithValue("#r3", ctxt);
con.Open();
insertCommand.ExecuteNonQuery();
}
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message, "UsingTest", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
No matter where's the try/catch placed, the exception will be caught without issues.
Old thread but still relevant. I arrived here looking for a way out of having a using statement inside of a using statement. I am happy with this, notwithstanding any future insightful comments that change my mind. ;) Conversations here helped. Thanks. Simplified for readability -
public DataTable GetExchangeRates()
{
DataTable dt = new DataTable();
try
{
logger.LogInformation($"Log a message.");
string conStr = _config.GetConnectionString("conStr");
using (SqlCommand cmd = new SqlCommand("someProc", new SqlConnection(conStr)))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection.Open();
dt.Load(cmd.ExecuteReader());
}
return dt;
}
catch (Exception ex)
{
logger.LogError(ex, ex.Message);
}
}
I am trying to pass a list of SqlCommand into a member function that holds the connection to the database.
public void CommitAsTransaction(List<SqlCommand> commands) {
SqlTransaction transaction = null;
SqlConnection connection = null;
try {
connection = this.CreateSqlConnection();
connection.Open();
transaction = connection.BeginTransaction("TransactionID");
foreach (SqlCommand cmd in commands) {
cmd.Transaction = transaction;
cmd.Connection = connection;
cmd.ExecuteNonQuery();
}
transaction.Commit();
}
catch (Exception ex) {
transaction.Rollback();
}
connection.Close();
}
This is what I currently have. The error occurs because the command seems to be being executed as in place and the transaction.Commit(); is never reached. I have seen many people doing it like this and am not sure what I am doing wrong.
PS: The issue is that the stored procedures that will be getting executed MUST all be run within a single transaction, I do not control these and they're encrypted, the reason they must be run in a transaction is because they create temp records in a table that has a PK requirement.
Can you use a transaction scope instead ?
Something like:
// place this code inside CommitAsTransaction
using (TransactionScope scope = new TransactionScope())
{
Boolean AllOK = true;
SqlConnection connection = this.CreateSQLConnection();
try
{
connection.Open()
}
catch (Exception e)
{
// deal with it how you need to
AllOK = false;
}
if (AllOK)
{
foreach(SQlCommand cmd in Commands)
{
try
{
cmd.Connection = connection;
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
// Deal with it..
AllOK = false;
break;
}
}
if (AllOK)
{
scope.Complete();
try
{
connection.Close();
}
catch (Exception e)
{
// deal with it
}
}
}
}
Thanks so much. I ended up figuring it out on my own based on other peoples combined answers, as a thank you here is the code I used:
public List<Models.eConnectModels.eConnStatus> CommitAsTransaction(List<SqlCommand> commands)
{
SqlTransaction transaction = null;
SqlConnection connection = null;
List<eConnStatus> ErrorList = new List<eConnStatus>();
try
{
connection = this.CreateSqlConnection();
connection.Open();
transaction = connection.BeginTransaction(IsolationLevel.ReadUncommitted, "TransactionID");
foreach (SqlCommand cmd in commands)
{
eConnStatus curErr = new eConnStatus();
cmd.Transaction = transaction;
cmd.Connection = connection;
SqlParameter errorString = cmd.Parameters.Add("#oErrString", SqlDbType.VarChar);
errorString.Direction = ParameterDirection.Output;
errorString.Size = 8000;
SqlParameter errorStatus = cmd.Parameters.Add("#O_iErrorState", SqlDbType.Int);
errorStatus.Direction = ParameterDirection.Output;
cmd.ExecuteNonQuery();
curErr.ErrorState = (int)cmd.Parameters["#O_iErrorState"].Value;
curErr.ErrorMessage = (string)cmd.Parameters["#oErrString"].Value;
ErrorList.Add(curErr);
}
transaction.Commit();
}
catch (Exception ex)
{
transaction.Rollback();
connection.Close();
throw ex;
}
connection.Close();
return ErrorList;
}