BeginTransaction() on sqltransaction freezes, how to use try catch to solve it? - c#

I'm using SqlTransaction transaction = connection.BeginTransaction() in my C# application to get data from SQLServer.
The problem I have when there is no connection to server (no internet connection), then my application just freezes and stops working, no exception, no error, just freezes.
I tried use try catch to catch error, but even then application just freezes, and the only option is to kill application. Can anyone help me to catch this error and istead of freezeing give me error - like Connection to server failed. Please check internet connection.
Here is my class code for connection:
public static class RequestID
{
// Methods
public static int GetID(string server, string database, string user, string pass)
{
int num = 0;
using (SqlConnection connection = new SqlConnection(string.Format("server={0};database={1};uid={2};pwd={3};Connect Timeout=900", new object[] { server, database, user, pass })))
{
SqlCommand command = new SqlCommand("SELECT Value_Int FROM Param WHERE code= 'counter'");
SqlCommand command2 = new SqlCommand("UPDATE Param SET Value_Int = Value_Int + 1 WHERE code= 'counter'");
if (connection.State != ConnectionState.Open)
{
connection.Open();
}
try
{
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
command.Connection = connection;
command.Transaction = transaction;
command2.Connection = connection;
command2.Transaction = transaction;
num = (int)command.ExecuteScalar();
command2.ExecuteNonQuery();
transaction.Commit();
}
catch (Exception)
{
transaction.Rollback();
throw;
}
finally
{
if (connection.State != ConnectionState.Closed)
{
connection.Close();
}
}
}
}
catch (Exception ex)
{
throw;
}
return num;
}
}
}
Problem is in line:
using (SqlTransaction transaction = connection.BeginTransaction())
Thanks in advance.
P.S. Application works just fine, the only problam so far then connection to internet lost. I wasn't able to find solution...

Your problem is because
connection.Open();
is outside of your try block so you will never hit the catch.
Move that inside your try block.

Related

How to ignore MySQL connection to database if there is no connection there

I want to make parallel database saving in my system. I have two destination that the database will be saved. First in the local computer (so I'm using localhost instead of the IPaddress) and the remote PC (i'm using the IP address to access it).
Here is my code :
static string MyConnectionString = "Server=localhost;Port=3306;Database=database freq logger;Uid=root;";
static string MyConnectionString2 = "Server=192.168.41.105;Port=3306;Database=database freq logger;Uid=irfan;";
MySqlConnection connection = new MySqlConnection(MyConnectionString);
MySqlConnection connection2 = new MySqlConnection(MyConnectionString2);
MySqlCommand cmd;
public void Read()
{
while (port.IsOpen)
{
try
{
if (port.BytesToRead > 0)
{
string message = port.ReadLine();
this.SetText(message);
connection.Open();
try
{
cmd = connection.CreateCommand();
cmd.CommandText = "INSERT INTO frequency(value)VALUES(#message)";
cmd.Parameters.AddWithValue("#message", message);
cmd.ExecuteNonQuery();
}
catch (Exception)
{
throw;
}
connection.Close();
if (connection2 != null && connection2.State == ConnectionState.Closed)
{
connection2.Open();
try
{
cmd = connection2.CreateCommand();
cmd.CommandText = "INSERT INTO frequency(value)VALUES(#message)";
cmd.Parameters.AddWithValue("#message", message);
cmd.ExecuteNonQuery();
}
catch (Exception)
{
throw;
}
connection2.Close();
}
}
}
catch (TimeoutException) { }
}
}
So I have 2 connectionsql (connection1 and connection2).
And I want to ignore the connection2 althought the connection is not connect. The connection is ethernet LAN. So when I unplug the LAN, I hope my program still running.
I always get the error (when I suddenly unplug the ethernet when the program running) in the "connection2.Open();".
I need your help, thank you
Don't try to monitor the connection pro-actively, just trap the resulting Exception and ignore it. Your problem is that your Connection2.Open() is not within the Try{} Catch{} block but outside it.
Try this
try
{
connection2.Open();
cmd = connection2.CreateCommand();
cmd.CommandText = "INSERT INTO frequency(value)VALUES(#message)";
cmd.Parameters.AddWithValue("#message", message);
cmd.ExecuteNonQuery();
connection2.Close();
}
catch
{
// Do nothing - this should continue to work without being able to make the connection
}

the operation is not valid for the state of the transaction

Below is the code and i am getting error on opening of connection.The connection state when this is executed is closed.
using (SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnStr"].ConnectionString))
{
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = cmdType;
cmd.CommandText = CommandName;
//cmd.Parameters.AddRange(pars);
if (pars != null)
{
cmd.Parameters.AddRange(pars);
}
try
{
**if (con.State != ConnectionState.Open)
{
con.Open();
}**
result = cmd.ExecuteNonQuery();
}
catch
{
throw;
}
finally
{
con.Close();
}
}
Its all in your IF Condition.
Your IF statement might be true even when ConnectionState is broken, because it is not equal to open.
Then it will go and try to open the connection, but it is already open and is broken. So, it would not be able to open it again.
Just get rid of that IF condition and try executing it.

in a "using" block is a SqlConnection closed on return or exception?

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);
}
}

multiple sqltransactions in single sqlconnection

I have some code that I want to execute as follows. But I keep getting the exception "This SqlTransaction has completed; it is no longer usable" on the 2nd iteration. Could someone help me point out what I am doing wrong here? Thanks!
SqlConnection cn = (SqlConnection)SqlConnectionManager.Instance.GetUserConnection(user);
cn.Open();
try
{
foreach (Master mRecord in masterList)
{
if (sqlTransaction == null)
sqlTransaction = cn.BeginTransaction();
SqlCommand cm = cn.CreateCommand();
cm.Transaction = sqlTransaction;
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "pr_InsertRecords";
try
{
cm.ExecuteNonQuery();
Debug.WriteLine("Auditor.Write: end sql table value param");
sqlTransaction.Commit();
sqlTransaction.Dispose();
}
catch (Exception Ex)
{
Debug.WriteLine(" Exception message: " + Ex.Message);
if (Ex.InnerException != null)
{
Debug.WriteLine("Inner exception message" + Ex.InnerException.Message);
}
sqlTransaction.Rollback();
}
}
}
finally
{
cn.Close();
}
Inside the loop you either commit or rollback, but you do not reset the reference to null. SqlTransaction in general is not used as this, is used in a using() block, just as a SqlConnection is:
using (SqlConnection cn = SqlConnectionManager.Instance.GetUserConnection(user))
{
foreach (Master mRecord in masterList)
{
try
{
using (SqlTransaction sqlTransaction = cn.BeginTransaction())
{
using (SqlCommand cm = cn.CreateCommand())
{
cm.Transaction = sqlTransaction;
cm.CommandType = CommandType.StoredProcedure;
cm.CommandText = "pr_InsertRecords";
cm.ExecuteNonQuery();
}
sqlTransaction.Commit();
Debug.WriteLine("Auditor.Write: end sql table value param");
}
}
catch (Exception Ex)
{
Debug.WriteLine(" Exception message: " + Ex.Message);
}
}
Try setting your sqlTransaction object to null after disposing it. Side note, you really should be wrapping those IDisposable objects in using blocks so Dispose is called at all times.
sqlTransaction.Commit();
sqlTransaction.Dispose();
sqlTransaction = null;
You need to create a new SqlTransaction object on each iteration or move the transaction completely outside the loop if you are wanting all the operations inside the loop to occur in a single transaction. Once you commit a transaction, it is necessary to call BeginTransaction again on the connection to start a new one. You cannot reuse the old transaction object.

Commit multiple SqlCommands with SqlTransaction

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;
}

Categories