I am reviewing a piece of code in a application and I came to something very strange in regard to connecting to database.
It is executing queries without opening the connection like this:
using (sqlConnection1 = new SqlConnection(connString)
{
SqlCommand comm = new SqlCommand(query,sqlConnection1);
// ... parameters are handled here...
SqlDataAdapter ad = new SqlDataAdapter(comm);
ds = new DataSet();
ad.FillSchema(ds, SchemaType.Source);
ad.Fill(ds);
}
Shouldnt it fail because of connection is not open? I actually tested this in separate project and it worked.
If the connection is closed, using SqlDataAdapter.Fill will open the connection
http://msdn.microsoft.com/en-us/library/377a8x4t.aspx
Per the documentation, SqlDataAdapter will open the conenction if it isn't already open, and return it to its previous state.
The connection object associated with the SelectCommand must be valid, but it does not need to be open. If the connection is closed before FillSchema is called, it is opened to retrieve data, then closed. If the connection is open before FillSchema is called, it remains open.
Fill also behaves in the same manner
Refer MSDN
The Fill method implicitly opens the Connection that the DataAdapter
is using if it finds that the connection is not already open. If Fill
opened the connection, it will also close the connection when Fill is
finished. This can simplify your code when dealing with a single
operation such as a Fill or an Update.
This means that after da.Fill(ds, "Test"); your connection is closed by the method itself. But you need it open for the following Update (and that fails)
From SqlDataAdapter.Fill method;
The Fill method retrieves rows from the data source using the SELECT
statement specified by an associated SelectCommand property. The
connection object associated with the SELECT statement must be valid,
but it does not need to be open. If the connection is closed before Fill is called, it is opened to retrieve data, then closed. If the
connection is open before Fill is called, it remains open.
Also FillSchema method does same thing.
Related
I have a C# program that connects to a remote server to query data. The data is quite big so the query takes about 2 mins to finish. During this 2 min window, the internet went down. This resulted in the job being unable to finish with the program stuck in the getting data routine.
It established connection but during the select query it was cut off. Setting the command timeout to 30 seconds did not work. I need the query to fail when encountering this error because the program can handle failure but it cannot handle being stuck. Thanks!
UPDATE: included code
OracleConnection connection = new OracleConnection(connectionstring);
OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(new OracleCommand(query, connection));
oracleDataAdapter.SelectCommand.CommandTimeout = 30;
DataSet dataSet = new DataSet();
try
{
oracleDataAdapter.Fill(dataSet, table); //Hangs on this line when connection is lost
return dataSet;
}
catch
{
throw;
}
finally
{
dataSet.Dispose();
oracleDataAdapter.Dispose();
}
UPDATE AGAIN:
What I need to do is handle this situation because I don't want a dangling process.
Simplest would be once the connection is lost is that the program will throw an error. That is what I don't know how to do. I assumed that the commandtimeout will fix it but it did not.
There are a few duplicates reporting this problem, eg: System being hang when the connection is lost while adapter is filling the datatables
I found a good thread on MSDN where the OP answers:
I have solved this problem a while back, sorry i forgot to come and let you all know. I worked out that the code stopped executing at that line because (for some reason) there was already an open connection to the database.
Since DA.Fill would open a connection itself if there wasnt one previously opened, it was having a hissy fit and bombing out.
I solved this by putting Connection.Close(); before and after any connection to the database is needed.
Based on this we can see you are not explicitly opening a Connection to the Database. Suggest you do a:
connection.Open();
Also follow Steve Py's answer with the using to confirm you are closing the connection and disposing unmanaged resources.
I see a couple issues with your statement, assuming it's using ODP.Net. Try the following:
DataSet dataSet = new DataSet();
using (OracleConnection connection = new OracleConnection(connectionstring))
{
using (OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(new OracleCommand(query, connection)))
{
oracleDataAdapter.Fill(dataSet, table);
}
}
return dataSet;
The using blocks will handle disposing of the connection and data adapter. In your example the connection did not get disposed which may have been part of your issue. Additionally I don't think you want to dispose the dataset if you intend to return it.
Since you were bubbling up the exception with a Throw I removed the exception handling. Keep in mind that this will bubble the exception so somewhere in your calling code chain you will need to catch the exception and handle it. If the app is just sitting there then be wary of any empty "catch" blocks eating exceptions.
Updated answer:
DataSet dataset = new DataSet();
using (OracleConnection connection = new OracleConnection(connection))
{
using (OracleDataAdapter oracleDataAdapter = new OracleDataAdapter(new OracleCommand(query, connection)))
{
oracleDataAdapter.SelectCommand.CommandTimeout = 30;
connection.Open();
oracleDataAdapter.Fill(dataset, table);
}
}
return dataset;
I have below code and I am getting exception:
There is already an open DataReader associated with this Connection which must be closed first.
I am using Visual Studio 2010/.Net 4.0 and MySQL for this project. Basically I am trying to run another SQL statement while using data reader to do my other task. I am getting exception at line cmdInserttblProductFrance.ExecuteNonQuery();
SQL = "Select * from tblProduct";
//Create Connection/Command/MySQLDataReader
MySqlConnection myConnection = new MySqlConnection(cf.GetConnectionString());
myConnection.Open();
MySqlCommand myCommand = new MySqlCommand(SQL, myConnection);
MySqlDataReader myReader = myCommand.ExecuteReader();
myCommand.Dispose();
if (myReader.HasRows)
{
int i = 0;
// Always call Read before accessing data.
while (myReader.Read())
{
if (myReader["frProductid"].ToString() == "") //there is no productid exist for this item
{
strInsertSQL = "Insert Into tblProduct_temp (Productid) Values('this istest') ";
MySqlCommand cmdInserttblProductFrance = new MySqlCommand(strInsertSQL, myConnection);
cmdInserttblProductFrance.ExecuteNonQuery(); //<=====THIS LINE THROWS "C# mySQL There is already an open DataReader associated with this Connection which must be closed first."
}
}
}
You are using the same connection for the DataReader and the ExecuteNonQuery. This is not supported, according to MSDN:
Note that while a DataReader is open, the Connection is in use
exclusively by that DataReader. You cannot execute any commands for
the Connection, including creating another DataReader, until the
original DataReader is closed.
Updated 2018: link to MSDN
Always, always, always put disposable objects inside of using statements. I can't see how you've instantiated your DataReader but you should do it like this:
using (Connection c = ...)
{
using (DataReader dr = ...)
{
//Work with dr in here.
}
}
//Now the connection and reader have been closed and disposed.
Now, to answer your question, the reader is using the same connection as the command you're trying to ExecuteNonQuery on. You need to use a separate connection since the DataReader keeps the connection open and reads data as you need it.
Just use MultipleActiveResultSets=True in your connection string.
Add MultipleActiveResultSets=true to the provider part of your connection string
example in the file appsettings.json
"ConnectionStrings": {
"EmployeeDBConnection": "server=(localdb)\\MSSQLLocalDB;database=YourDatabasename;Trusted_Connection=true;MultipleActiveResultSets=true"}
You are trying to to an Insert (with ExecuteNonQuery()) on a SQL connection that is used by this reader already:
while (myReader.Read())
Either read all the values in a list first, close the reader and then do the insert, or use a new SQL connection.
The issue you are running into is that you are starting up a second MySqlCommand while still reading back data with the DataReader. The MySQL connector only allows one concurrent query. You need to read the data into some structure, then close the reader, then process the data. Unfortunately you can't process the data as it is read if your processing involves further SQL queries.
This exception also happens if you don't use transaction properly. In my case, I put transaction.Commit() right after command.ExecuteReaderAsync(), did not wait with the transaction commiting until reader.ReadAsync() was called. The proper order:
Create transaction.
Create reader.
Read the data.
Commit the transaction.
You have to close the reader on top of your else condition.
In my case, I was awaiting an async call, but in the calling scope, I was not awaiting that method that I was making the call in. So, the calling scope was continuing on while my connection was still open.
called scope:
protected override async Task AfterProcessing()
{
var result = await Stats.WriteAsync();
Log.Information("Stopping");
}
calling scope:
public virtual async Task Run()
{
BeforeProcessing();
try
{
Process();
}
finally
{
AfterProcessing(); // this line was missing an "await"
}
}
There is another potential reason for this - missing await keyword.
I'm creating an application where I connect to an Access database and do several updates. Since I'm not a database programmer this is also a learning experience. I found the following code online but it didn't work until I added the connection.open() line.
So here's my question. I thought that like in other using cases like creating a file it would automatically open the connection and then dispose at the last }. Why did I have to explicitly call out the open command after creating a new connection?
private static void GetAllTableAndColumnNames(string connectionString)
{
using (OdbcConnection connection =
new OdbcConnection(connectionString))
{
connection.Open();
DataTable tables = connection.GetSchema("Tables");
DataTable columns = connection.GetSchema("Columns");
foreach (DataRow row in columns.Rows)
{
Console.WriteLine(row["COLUMN_NAME"].ToString());
Console.WriteLine(row["TABLE_NAME"].ToString());
}
Console.Read();
}
}
Here's the error I got on runtime without the open command.
An unhandled exception of type 'System.InvalidOperationException' occurred in System.Data.dll
Additional information: Invalid operation. The connection is closed.
When the code reaches the end of a using block and it knows that the Connection object is about to be destroyed it "does you a favour" by ensuring that the connection is properly closed. That is because simply destroying the Connection object without notifying the server would be inconsiderate: server connections are often precious commodities and leaving an orphaned connection "open" on the server would be a Bad Thing.
On the other hand, automatically opening a connection when the Connection object is created (i.e., the using statement itself) would not necessarily be a Good Thing. Perhaps you want to create your Connection object, and then create a whole bunch of other objects that depend on the Connection object (e.g., Command, DataAdapter, etc.). Does the connection actually need to be open while that is taking place? If not, then having the connection open for the whole time might also be inconsiderate if you are connecting to a busy server.
Or, to put it another way, there are very legitimate reasons why a Connection object might switch states between "open" and "closed" while it exists, but the only state it should be in at the moment of its demise is "closed". That's why there is the "auto-close" behaviour but not a corresponding "auto-open".
Using clause is designed to close automaticlly resources when the variable is out of scope. The behaviour in the constructor depends on the implementation: DbConnection descendants don't open the conection in the constructor.
I think that this is because constructor overloads: some overloads doesn't take arguments, so can't open the database.
I am creating desktop application in winform that will use Sqlite Database.
So I created Sqlite Helper class that uses System.Data.SQLite and each method of that Helper class opens and closes connection.
But now I also added ability to attach additional databases but after Connection is Closed, all attached databases gets lost.
To correct this I modified the class so that the connection is opened in constructor and remains open.
After the application ends, I want that connection to close without explicitly calling the Close method.
Any suggestions how to do that?
Keeping the connection open for the lifetime of your application is not a good way to go.
I suggest to not follow this route.
On the contrary, I will try to encapsulate the functionality to attach a database inside a method that could be called on the need to use basis.
For example:
private static void AttachDB(string fileDB, string aliasName, SQLiteConnection cn)
{
string sqlText = string.Format("ATTACH '{0}' AS {1}", fileDB, aliasName)
SQLiteCommand cmd = new SQLiteCommand(sqlText, cn)
cmd.ExecuteNonQuery();
}
then in your code
using(SQLiteConnection cn = new SQLiteConnection(GetConnectionString()))
{
AttachDB(#"C:\SQLite\UserData.sqlite3", "UserData", cn);
// Do your code here
}
Close should not disconnect your database but this will only work when .NET connection pooling mechanism is on. Make sure you have that enabled in your connection string:
Data Source=filename;Version=3;Pooling=True;Max Pool Size=100;
Depending on how your class is defined, you can use Dispose or a destructor. Or, explicitly call Close() at the end of the program (from within Main, after Run...).
In C# there is a special syntax for such situation:
using(var connection = new Connection())
{
//work with connection
}
it compiles to something like:
Connection connection = null;
try
{
connection = new Connection();
//your operations
}
finally
{
connection.Dispose();
}
on calling Dispose() you close connection.
I have below code and I am getting exception:
There is already an open DataReader associated with this Connection which must be closed first.
I am using Visual Studio 2010/.Net 4.0 and MySQL for this project. Basically I am trying to run another SQL statement while using data reader to do my other task. I am getting exception at line cmdInserttblProductFrance.ExecuteNonQuery();
SQL = "Select * from tblProduct";
//Create Connection/Command/MySQLDataReader
MySqlConnection myConnection = new MySqlConnection(cf.GetConnectionString());
myConnection.Open();
MySqlCommand myCommand = new MySqlCommand(SQL, myConnection);
MySqlDataReader myReader = myCommand.ExecuteReader();
myCommand.Dispose();
if (myReader.HasRows)
{
int i = 0;
// Always call Read before accessing data.
while (myReader.Read())
{
if (myReader["frProductid"].ToString() == "") //there is no productid exist for this item
{
strInsertSQL = "Insert Into tblProduct_temp (Productid) Values('this istest') ";
MySqlCommand cmdInserttblProductFrance = new MySqlCommand(strInsertSQL, myConnection);
cmdInserttblProductFrance.ExecuteNonQuery(); //<=====THIS LINE THROWS "C# mySQL There is already an open DataReader associated with this Connection which must be closed first."
}
}
}
You are using the same connection for the DataReader and the ExecuteNonQuery. This is not supported, according to MSDN:
Note that while a DataReader is open, the Connection is in use
exclusively by that DataReader. You cannot execute any commands for
the Connection, including creating another DataReader, until the
original DataReader is closed.
Updated 2018: link to MSDN
Always, always, always put disposable objects inside of using statements. I can't see how you've instantiated your DataReader but you should do it like this:
using (Connection c = ...)
{
using (DataReader dr = ...)
{
//Work with dr in here.
}
}
//Now the connection and reader have been closed and disposed.
Now, to answer your question, the reader is using the same connection as the command you're trying to ExecuteNonQuery on. You need to use a separate connection since the DataReader keeps the connection open and reads data as you need it.
Just use MultipleActiveResultSets=True in your connection string.
Add MultipleActiveResultSets=true to the provider part of your connection string
example in the file appsettings.json
"ConnectionStrings": {
"EmployeeDBConnection": "server=(localdb)\\MSSQLLocalDB;database=YourDatabasename;Trusted_Connection=true;MultipleActiveResultSets=true"}
You are trying to to an Insert (with ExecuteNonQuery()) on a SQL connection that is used by this reader already:
while (myReader.Read())
Either read all the values in a list first, close the reader and then do the insert, or use a new SQL connection.
The issue you are running into is that you are starting up a second MySqlCommand while still reading back data with the DataReader. The MySQL connector only allows one concurrent query. You need to read the data into some structure, then close the reader, then process the data. Unfortunately you can't process the data as it is read if your processing involves further SQL queries.
This exception also happens if you don't use transaction properly. In my case, I put transaction.Commit() right after command.ExecuteReaderAsync(), did not wait with the transaction commiting until reader.ReadAsync() was called. The proper order:
Create transaction.
Create reader.
Read the data.
Commit the transaction.
You have to close the reader on top of your else condition.
In my case, I was awaiting an async call, but in the calling scope, I was not awaiting that method that I was making the call in. So, the calling scope was continuing on while my connection was still open.
called scope:
protected override async Task AfterProcessing()
{
var result = await Stats.WriteAsync();
Log.Information("Stopping");
}
calling scope:
public virtual async Task Run()
{
BeforeProcessing();
try
{
Process();
}
finally
{
AfterProcessing(); // this line was missing an "await"
}
}
There is another potential reason for this - missing await keyword.