Using DbConnection without opening it first - c#

I am accessing a DB using the generic DbConnection provided by DbProviderFactories and I have observed that I don´t need to call Open before using the connection. I provide a sample code that is working (either using "System.Data.SqlClient" or "Oracle.DataAccess.Client" as the providerInvariantName parameter). I have performed all CRUD operations with similar code without explicitly calling Open on the connection, without any noticeable error.
I understand that I don´t need to close it, since the using statement takes care of closing and disposing the connection.
But, when is the connection opened in this code, then? Is it automatically opened when I call Fill on the associated DataAdapter? Is there any consequence of not explicitly calling Open on the connection object before using it?
Because if it is unnecesary and I can save myself a couple of lines of code I will sure do. ;-)
DbProviderFactory myFactoryProvider = DbProviderFactories.GetFactory("System.Data.SqlClient");// same with "Oracle.DataAccess.Client"
using (var myConnection = myFactoryProvider.CreateConnection())
using (var myCommand = myFactoryProvider.CreateCommand())
{
try
{
// Set up the connection
myConnection.ConnectionString = _someConnectionString;
myCommand.Connection = myConnection;
myCommand.CommandText = "SELECT * FROM SOME_TABLE";
// Create DataAdapter and fill DataTable
DbDataAdapter dataAdapter = myFactoryProvider.CreateDataAdapter();
dataAdapter.SelectCommand = myCommand;
DataTable myTable = new DataTable();
dataAdapter.Fill(myTable);
// Read the table and do something with the data
foreach (DataRow fila in myTable.Rows)
{
// Do something
}
}
catch (Exception e)
{
string message = e.ToString();
throw;
}
} //using closes and disposes the connection and the command

The connection to the db should be established and opened when the statement
dataAdapter.Fill(myTable);
runs, so your code goes well as is

Related

Why is my code leaking connections?

Question:
Why is the following code leaking connections ?
public System.Data.DataTable GetDataTable()
{
System.Data.DataTable dt = new System.Data.DataTable();
string strConnectionString = "Data Source=localhost;Initial Catalog=MyDb;User Id=SomeOne;Password=TopSecret;Persist Security Info=False;MultipleActiveResultSets=False;Packet Size=4096;";
System.Data.SqlClient.SqlConnectionStringBuilder csb = new System.Data.SqlClient.SqlConnectionStringBuilder(strConnectionString);
csb.IntegratedSecurity = true;
string strSQL = "SELECT * FROM T_Benutzergruppen";
using (System.Data.SqlClient.SqlConnection sqlcon = new System.Data.SqlClient.SqlConnection(csb.ConnectionString))
{
using (System.Data.SqlClient.SqlCommand cmd = new System.Data.SqlClient.SqlCommand(strSQL, sqlcon))
{
if (sqlcon.State != System.Data.ConnectionState.Open)
{
sqlcon.Open();
}
// First attempt
//System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", sqlcon);
//sqlda.Fill(dt);
cmd.ExecuteNonQuery();
}
if(sqlcon.State != System.Data.ConnectionState.Closed)
sqlcon.Close();
}
//sqlcon.ConnectionString = csb.ConnectionString;
// Second attempt
//System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", csb.ConnectionString);
//sqlda.Fill(dt);
return dt;
}
If I go into SQL-Server activity monitor, I see Session 68
SELECT * FROM T_Benutzergruppen
Additional question:
If question:
If I comment out everything except the ConnectionStringBuilder, and only execute the below code in this function, why does it leak a connection, too ?
// Second attempt
System.Data.SqlClient.SqlDataAdapter sqlda = new System.Data.SqlClient.SqlDataAdapter("SELECT * FROM T_Benutzer", csb.ConnectionString);
sqlda.Fill(dt);
Note:
The executenonquery makes no sense, it's just there for testing purposes.
If I let it run in the debugger, I see that
sqlcon.Close();
get's executed, so the problem is not the
if(sqlcon.State != System.Data.ConnectionState.Closed)
Connection Pooling. Don't worry about it.
This is normal behavior.
http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.100).aspx
ADO.Net pools connections so that they can be re-used because they are relatively expensive to create.
Connecting to a database server typically consists of several time-consuming steps. A physical channel such as a socket or a named pipe must be established, the initial handshake with the server must occur, the connection string information must be parsed, the connection must be authenticated by the server, checks must be run for enlisting in the current transaction, and so on.
In practice, most applications use only one or a few different configurations for connections. This means that during application execution, many identical connections will be repeatedly opened and closed. To minimize the cost of opening connections, ADO.NET uses an optimization technique called connection pooling.
http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.100).aspx
Also, there is no need to explicitly call .Close(). Your using block will call IDisposable.Dispose(), which will close the connection properly.

"Invalid attempt to call Read when reader is closed" when using a SqlDataReader

1) I have the following codes:
private static sqlDataReader gCandidateList = null;
public SqlDataReader myCandidateList
{
set
{
gCandidateList = value;
}
get
{
return gCandidateList;
}
}
2) In FormA I have:
sqlConn.ConnectionString = mySettings.myConnString;
sqlConn.Open();
SqlCommand cmdAvailableCandidate = new SqlCommand(tempString, sqlConn);
SqlDataReader drAvailableCandidate = cmdAvailableCandidate.ExecuteReader();
mySettings.myCandidateList = drAvailableCandidate;
sqlConn.Close();
3) In FormB I want to reuse the data saved in myCandidatList so I use:
SqlDataReader drCandidate = mySettings.myCandidateList;
drCandidate.Read();
4) I then got the error "Invalide attempt to call Read when reader is closed."
5) I tried mySettings.myCandidateList.Read() in (3) above and again received the same error message.
6) How can I re-open SqlDataReader drCandidate to read data?
7) Would appreciate very much for advise and help, please.
You can't read reader once the connection is closed or disposed. If you want to use those rows (fetch result) later in your code you need to create a List or DataTable.
For instance,
System.Data.DataTable dt = new System.Data.DataTable();
dt.Load(drAvailableCandidate);
If you want to use the datareader at later stage, you have to specify the same as a parameter to the ExecuteReader Method. Your code in FormA should be changed as below.
sqlConn.ConnectionString = mySettings.myConnString;
sqlConn.Open();
SqlCommand cmdAvailableCandidate = new SqlCommand(tempString, sqlConn);
SqlDataReader drAvailableCandidate = cmdAvailableCandidate.ExecuteReader(CommandBehavior.CloseConnection);
mySettings.myCandidateList = drAvailableCandidate;
sqlConn.Close();
Make sure to dispose the datareader once it is used, as the connection to the database will be held open till the datareader is closed. Better change your code in FormB as below.
using (mySettings.myCandidateList)
{
mySettings.myCandidateList.Read();
}
You're closing the connection before you attempt to read from the reader. That won't work.
When you call Close on the SqlConnection object (sqlConn.Close();) it closes the connection and your data reader. That is why you are getting the error when you try to read from your SqlDataReader from FormB.
What you need to do is change the definition of your myCandidateList property to instead return a representation of the data that you have extracted from the your drAvailableCandidate reader.
Essentially what you need to do is iterate through the rows in the drAvailableCandidate object, extract the values and cache them in your property for later retrieval.
Just to add to the answers already given, if you're using async/await then it's easy to get caught out with this by not awaiting an operation inside a using block of a SqlConnection. For example, doing the following can give the reported error
public Task GetData()
{
using(new SqlConnection(connString))
{
return SomeAsyncOperation();
}
}
The problem here is we're not awaiting the operation inside the using, therefore it's being disposed of before we actually execute the underling async operation. Fairly obvious, but has caught me out before.
The correct thing to do being to await inside the using.
public async Task GetData()
{
using(new SqlConnection(connString))
{
await SomeAsyncOperation();
}
}

C# MySqlConnection won't close

I have an application that fires a mysql command (query) "show databases", the query works and returns properly but I can't close my connections. The user I used had 24 connections allowed at the same time so the problem popped up further down my program but reducing the allowed connections to 2 shows me that I can't even close the first query (which isn't in a loop). The code is the following:
protected override Dictionary<string, Jerow_class_generator.Database> loadDatabases()
{
MySqlConnection sqlCon = new MySqlConnection(this.ConnectionString);
sqlCon.Open();
MySqlCommand sqlCom = new MySqlCommand();
sqlCom.Connection = sqlCon;
sqlCom.CommandType = CommandType.Text;
sqlCom.CommandText = "show databases;";
MySqlDataReader sqlDR;
sqlDR = sqlCom.ExecuteReader();
Dictionary<string, Jerow_class_generator.Database> databases = new Dictionary<string, Jerow_class_generator.Database>();
string[] systemDatabases = new string[] { "information_schema", "mysql" };
while (sqlDR.Read())
{
string dbName = sqlDR.GetString(0);
if (!systemDatabases.Contains(dbName))
{
databases.Add(sqlDR.GetString(0), new MySQL.Database(dbName, this));
}
}
sqlCom.Dispose();
sqlDR.Close();
sqlCon.Close();
sqlCon.Dispose();
return databases;
}
P.S. The 'New MySQL.Database(dbName, this));' is my owm made class which only stores the DB structure, could be considered irrelevant.
The exact error I get is 'max_user_connections'. on the connection.open line of the next time a query needs to be fired.
Rather than keeping track of all the Open/Close/Dispose calls all over the place, I'd recommend just replacing all of those with using statements. This will make sure the expected scope of each object is clear and that it will be destroyed/disposed upon exiting that scope.
Close() nor using will help alone with your problem because ADO.NET is using its own connection pooling and connections are by default not closed until program is closed. There are few options to solve this, but consider performance implications and is this really desired behavior for your application.
Add ";Pooling=False" to your connection string.
SqlConnection.ClearPool Method
SqlConnection.ClearAllPools Method
For more information read: SQL Server Connection Pooling (ADO.NET)
Along with the using suggestions above, when creating your sqlDR variable you should use the CloseConnection command behavior to close the actual connection if that is your intended action. As noted in the documentation here.
When the command is executed, the associated Connection object is closed when the associated DataReader object is closed.
So your code to instantiate your reader would look like this:
//to instantiate your variable
MySqlDataReader sqlDR;
sqlDR = sqlCom.ExecuteReader(CommandBehavior.CloseConnection);
//closing your datareader reference here will close the connection as well
sqlDR.Close();
If you wrap all your code in a using block using the above method, you don't need any of those Close() or Dispose() methods other than the sqlDR.Close();
when use "using" key word what happen is.when the garbage collector activate it first dispose objects which was declred in using statement.
I recommend using connection pooling in combination with the MySqlHelper class, passing the connection string as the first argument. That allows MySQL to open the connection if necessary, or keep it open according to the pooling cfg, without you having to know about it.
I changed my code to use 1 connection and keep it open and when testing I came across an error that a datareader should be closed. Now since all my queries didn't close the dataReader object (I used dataTable.Load(cmd.ExecuteReader()).) I think the problem might be there.
Keeping 1 open connection worked perfectly so I don't know what caused the not closing problem. I gues it was the dataReader not closing by itself.
Close() will definitely help you close your.
using (MySqlConnection conn = GetConnection())
{
conn.Open();
using (MySqlCommand cmd = conn.CreateCommand())
{
if (conn.State != ConnectionState.Open)
{
conn.Open();
}
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "UserDetail";
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
list.Add(new Album()
{
Id = Convert.ToInt32(reader["UId"]),
Name = reader["FirstName"].ToString(),
ArtistName = reader["LastName"].ToString()
});
}
}
}
}
In the above code, you can see one if condition before opening the connection it will help you to reuse your already open connections check below code.
if (conn.State != ConnectionState.Open)
{
conn.Open();
}

Why isn't SqlConnection disposed/closed?

Given the method:
internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
var dataset = new DataSet();
SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
: new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]);
SqlCommand sqlcmd = sqlc.CreateCommand();
sqlcmd.CommandText = commandText;
var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
adapter.Fill(dataset);
return dataset;
}
Why is sqlc (the SqlConnection) not disposed/close after the calling method goes out of scope or sqlc has no more references?
EDIT 1:
Even wrapping it in using, I can still seeing the connection using (I have connection pooling turned off):
SELECT DB_NAME(dbid) as 'Database Name',
COUNT(dbid) as 'Total Connections'
FROM sys.sysprocesses WITH (nolock)
WHERE dbid > 0
GROUP BY dbid
EDIT 2:
Have some more debugging with help I got from here - the answer was the someone hard coded a connection string with pooling. Thanks for all the help - if I could, I would mark all the responses as answers.
C#'s garbage collection is non-deterministic but the language does provide a deterministic structure for resource disposal like this:
using (SqlConnection connection = new SqlConnection(...))
{
// ...
}
This will create a try/finally block which will ensure that the connection object is disposed regardless of what happens in the method. You really ought to wrap any instances of types that implement IDisposable in a using block like this as it will ensure responsibly resource management (of unmanaged resources like database connections) and also it gives you the deterministic control you are looking for.
Because c# is a garbage collected language, and garbage collection is not deterministic. The fact of it is that your sqlconnection is disposed. You just don't get to choose when.
Sql connections are a limited resource, and it's easily possible that you might create enough of them to run out. Write it like this instead:
internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
var dataset = new DataSet();
using (SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
: new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"]))
using (SqlCommand sqlcmd = sqlc.CreateCommand())
{
sqlcmd.CommandText = commandText;
var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
adapter.Fill(dataset);
}
return dataset;
}
Though in this case you might get away with it, because the .Fill() method is a strange beast:
If the IDbConnection is closed before Fill is called, it is opened to retrieve data and then closed.
So that means the Data Adapter should be taking care of it for you, if you start out with a closed connection. I'm much more concerned that you're passing in your sql command as a plain string. There have to be user parameters in your queries from time to time, and this means you're concatenating that data directly into the command string. Don't do that!! Using the SqlCommand's Paramters collection instead.
I agree with all the answers here plus a connection may be a wider scope than just a method. When you need to use your existing connection in different places the scenario changes a bit. Always make sure to call Dispose for all objects that implement IDisposable after you are done using them. This is a good practice so you don't end up with unused objects that the garbage collector can't decide what to do with them.
It will be, after the garbage collection does it's job. Same goes for opening a file stream for writing without closing it. It might get 'locked' even though the codes went out of scope.
I believe it has something to do with SqlConnection pooling. What you can do, and we do often at work is wrap the entire call in a using statement which causes it to call the dispose() method, hense closing the connection and disposing of the object
You could then do something like this instead:
internal static DataSet SelectDataSet(String commandText, DataBaseEnum dataBase)
{
var dataset = new DataSet();
using(SqlConnection sqlc = dataBase == DataBaseEnum.ZipCodeDb
? new SqlConnection(ConfigurationManager.AppSettings["ZipcodeDB"])
: new SqlConnection(ConfigurationManager.AppSettings["WeatherDB"])) {
SqlCommand sqlcmd = sqlc.CreateCommand();
sqlcmd.CommandText = commandText;
var adapter = new SqlDataAdapter(sqlcmd.CommandText, sqlc);
adapter.Fill(dataset);
return dataset;
}
}

Sqlite database locked

I'm using asp.net c# and upload a SqLite database to a server and then I do some inserting and updating. The problem is that sometimes (I think it's when somethings go wrong with the updating or so) the database gets locked. So the next time I try to upload a file again it's locked and I get an error saying "The process cannot access the file because it is being used by another process". Maybe the database file isn't disposed if something goes wrong during the transaction? The only thing to solve this problem is restarting the server.
How can I solve it in my code so I can be sure it's always unlocked even if something goes wrong?
This is my code:
try
{
string filepath = Server.MapPath("~/files/db.sql");
//Gets the file and save it on the server
((HttpPostedFile)HttpContext.Current.Request.Files["sqlitedb"]).SaveAs(filepath);
//Open the database
SQLiteConnection conn = new SQLiteConnection("Data Source=" + filepath + ";Version=3;");
conn.Open();
SQLiteCommand cmd = new SQLiteCommand(conn);
using (SQLiteTransaction transaction = conn.BeginTransaction())
{
using (cmd)
{
//Here I do some stuff to the database, update, insert etc
}
transaction.Commit();
}
conn.Close();
cmd.Dispose();
}
catch (Exception exp)
{
//Error
}
You could try placing the Connection in a using block as well, or calling Dispose on it:
//Open the database
using (SQLiteConnection conn = new SQLiteConnection("Data Source=" + filepath + ";Version=3;")) {
conn.Open();
using (SQLiteCommand cmd = new SQLiteCommand(conn)) {
using (SQLiteTransaction transaction = conn.BeginTransaction()) {
//Here I do some stuff to the database, update, insert etc
transaction.Commit();
}
}
}
This will ensure that you're disposing of the connection object's correctly (you're not at the moment, only closing it).
Wrapping them in using blocks ensures that Dispose is called even if an exception happens - it's effectively the same as writing:
// Create connection, command, etc objects.
SQLiteConnection conn;
try {
conn = new SQLiteConnection("Data Source=" + filepath + ";Version=3;");
// Do Stuff here...
}
catch (exception e) {
// Although there are arguments to say don't catch generic exceptions,
// but instead catch each explicit exception you can handle.
}
finally {
// Check for null, and if not, close and dispose
if (null != conn)
conn.Dispose();
}
The code in the finally block is going to be called regardless of the exception, and helps you clean up.
An asp.net application is multithreaded in the server.
You can't do simultaneous writing (insert, select, update...) because the whole db is locked. Simultaneously selecting is allowed when no writing is happening.
You should use the .NET ReaderWriterLock class: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock.aspx
Shouldn't you do cmd.Dispose() before conn.Close()? I don't know if it makes any difference, but you generally want to clean things up in the opposite of initialization order.
In short, SQLite handles unmanaged resources slightly differently than other providers. You'll have to explicitly dispose the command (which seems to work even if you are working with the reader outside of the using() block.
Read this thread for more flavor:
http://sqlite.phxsoftware.com/forums/p/909/4164.aspx

Categories

Resources