I have a C# application that reads/writes from/to an Access Database. I do this using an OleDbConnection.
Before a read / write, I want to check that my database connection is open. It should be straight-forward....
if (Connection.State != ConnectionState.Open) Connection.Open();
While this generally works well, it is not working for situations where network access is interrupted. The Connection.State is still recorded as 'Open', so I'd get an exception. So, I tried this:
Connection.ResetState();
if (Connection.ConnectionState(DatabaseType) != ConnectionState.Open) Connection.Open();
Nope... That's not working either, as the ResetState() method isn't actually resetting the state.
So I tried this extension method (a bit ugly...)
public static ConnectionState ConnectionState(this OleDbConnection connection, DatabaseType type)
{
connection.ResetState();
if (type == DatabaseType.Access)
{
//Reset state might not work... Check that the datasource is locatable
if (!File.Exists(connection.DataSource)) return System.Data.ConnectionState.Closed;
return connection.State;
}
return connection.State;
}
This "sort of" works, in that it correctly identifies that the DataSource can't be located. But then I get an exception when I try to open the database; not that it can't be found, but that its an invalid operation trying to open a connection that is already open!
I've spent about an hour trying to google to find a reliable way to get the true status of the database connection. Any other suggestions?
Correct way to use DbConnection is to create a new one for every command. Connection pooling means there is not usually a big overhead, and any network issues in between are sorted out automatically.
Make sure to Dispose correctly.
Related
My code looks like this:
void SomeFuncCalledConcurrently()
{
using(var connection = new MySqlConnection(mConnectionString))
{
connection.Open();
//DoStuff
connection.Close();
}
}
SomeFuncCalledConcurrently is called by multiple threads at once.
The problem is I get an exception that the connection is already open, even tho as far as I am aware, the connection pool is thread-safe, which means that I only need to create the MySqlConnection objects for each thread.
This is what I get:
System.InvalidOperationException: 'The connection is already open.'
Could the connection object be getting reused behind the scenes, due to having the same connection string? If that's the case, is there a way to disable this?
I have a question about closing an opened connection to a database in C#. Let's say we abandon the "using" method and use a try/catch/finally block to open and close the connection.
try
{
connection = new SqlConnection();
connection.Open();
}
catch (Exception ex)
{
// Do whatever you need with exception
}
finally
{
1.connection.Dispose();
2.if (connection != null)
{
connection.Dispose();
}
}
My question here is what exactly happens if only 1) in this code segment occurs. The connection should always be checked for null before disposed(closed), but what if it isn't, and we try to close a connection object that's null? (I'm interested in what happens to the opened connection, can this lead to a leak)
In the question, if connection.Dispose() is called on a null connection without the check, you cause a new exception that has not been handled, and everything that goes with that. Additionally, if this was done because the connection variable was set to null before the finally block without ensuring the connection was closed, it is possible to leak that open connection ... though as a practical matter it's rare to see code in the wild that knows to use a finally but also wants to set the connection to null.
Granting the lack of using (which is suspect, but whatever), I prefer this pattern:
finally
{
if (connection is IDisposable) connection.Dispose();
}
This still protects against null values* in the connection object, and is a closer mimic for what the using pattern was already doing behind the scenes.
Note, however, you're still missing one important feature of a using block, which is protection against something assigning null to your variable before the block closes. using blocks also protect your connection in a separate (hidden) variable, so you're sure you still have a valid reference at the end of the block (this is new in C# 8).
*(For completeness, the author of that linked tweet is the lead on the C# compiler team, so he should know, and he's not being ironic).
sc is a SQL connection passed in from the calling function
I'm using one SQL connection throughout my entire program and having each subfunction open and close it as needed. (I read this was fine, because the SQLConnection class has it's own connection pooling functionality)
string q = "this would be a query";
using (SqlCommand cmd = new SqlCommand(q, sc))
{
cmd.Parameters.Add("#ID", SqlDbType.Int);
cmd.Parameters["#ID"].Value = (an id that is passed in);
try
{
sc.Open();
using (var reader = cmd.ExecuteReader())
{
if(reader.read())
{ logic that might throw exception }
else
{ logic that might throw exception }
}
sc.Close();
}
catch (Exception e)
{
alert user, program does not halt but current function returns
}
}
So the connection opens and the command attempts to execute and some logic is performed that might throw an exception. (I'm not expecting it to) This function is part of a larger program that is processing a large dataset. If it fails DUE TO AN EXCEPTION it needs to note it, but it also needs to attempt to keep running.
Other parts of the program are sharing this connection and opening and closing it as they need it and I've used this basic template for all queries in the program.
It just occurred to me that if an exception occurred, the connection might not be closed. Am I correct in thinking that? My original concern when writing this is that the sc.Open() would be the thing that would throw an exception, but as I've used this in multiple places I've realized that this was short sighted because the connection could open and then any number of steps between the close could throw an exception.
Do I need additional logic here to make sure this connection is closed and the program can attempt to continue running?
If my understanding is correct that the connection needs to be closed in the event of an exception between the open and close I think I have 2 options :
try/catch between the open and close
sc.Close() in the catch block (Bonus concern : If the sc.Open() throws an exception and catch block tries to sc.Close() will an additional exception be thrown?)
You do not need to worry about closing the connection. The connection is closed automatically when it disposed by the using statement within which the connection is created.
In the event of an exception, the connection will still be disposed (and thus closed) because that's how a using statement is designed to work.
You have the State property of the SqlConnection that you can use to determine what state the last network operation left the connection in. This property is described here: https://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.state(v=vs.110).aspx
I would recommend reacting to exceptions in the SqlConnection (such as Open) and in the SqlCommand separately, because, in my experience, you will usually want to take different actions. Even with the overall approach you want to take,
if you can't open your connection, there is no point in preparing the query,
and you likely want to say something different about inability to open the connection than you would if the query failed. I would move the sc.Open() before the creation of the SqlCommand and try/catch around that.
Clarification on the above answer by #roryap - there is no need for sc.Close() if your connection is created in a using statement but from your question I guess it's not. In which case you should probably add a finally section to the try catch block and close the connection in there.
Its better that you close the connection in finally block
finally
{
sc.Close();
}
After try block is completed, the finally block will work.
In a case of an exception, finally block also works.
So the connection will closed in any case.
I hope this isn t too general a question.
I have quite a few winforms applications which connect to the same sql database.
On one of my servers the CPU is getting to 100% (which is an issue in itself which needs to be investigated).
So i'm getting a - 'The underlying Provider Failed to open'
So my issue is there are a lot of repository requests within the applications and i don t really want to put try catches around all of them - although i have done the following in the main method of one of them:
connDb1 == false;
while (connDb1 == false)
{
try
{
//code in here with various connection to db though repositories...
connDb1 = true;
}
catch (Exception)
{
connDb1 = false;
_keepItDry.AddTolistBox(DateTime.Now.ToLongDateString() + " " + DateTime.Now.ToLongTimeString() + ": Error connection to DB may have failed - try again... ", _listBoxLog);
Thread.Sleep(60000);//wait 1 minute and try again
}
}
Has anyone got a good solution for how to check if the db connection has been lost and retry without the application crashing.
Or is it a case of going through the applications and anywhere which connects error handle there.
I hope this makes sense.
Many thanks
Hello everyone i was hopping to get a little advice on how someone would go about doing something
i need to test sql connection for a main server, if the connection returns false then i need to set a variable that will tell the program to use it own local sql ce database
how would yall go about testing that connection then setting that variable?
Would yall agree on something like this
try
{
con.open();
standalone=false;
con.close();
}
catch
{
standalone=true;
con.close();
}
Not the best solution, but if you have a bunch of queries would be ok. Whenever you need to open a connection to your object you check if everything is ok with your first connection string. Otherwise your second conneciton string.
using (SqlConnection Conn = new SqlConnection(connectionString1))
{
try
{
Conn.Open();
// Here goes your statements for querying your db.
}
catch (Exception Ex)
{
using(SqlConnection Conn2 = new SqlConnection(connectionString2))
{
try
{
Conn2.Open();
// Here goes your statements for querying your db.
}
catch(Exception Ex2)
{
// Here goes your error handling code for the second connection
}
}
}
}
Although the above might be a solution to your problem, I should state a concern, which have arisen since I read your question. Suppose you connect to your first database and you do any tranasction you need with it. After a little time there comes a problem and you cannot connect to your first db. So you will connect to your second db. Then the data of the second db will be incosistent with the data you had, when you were using the first db.
You need to handle sqlexception and if one occurs you can then use your local connection
see http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqlconnection.open(v=vs.110).aspx