If I want to run multiple SELECT queries on different tables, can I use the same SqlDataReader and SqlConnection for all of them?? Would the following be wise?? (I typed this up fast, so it lacks try/catch):
MySqlCommand myCommand = new MySqlCommand("SELECT * FROM table1", myConnection);
myConnection.Open();
SqlDataReader myDataReader = myCommand.ExecuteReader();
while(myReader.Read())
{
//Perform work.
}
myCommand.commandText = "SELECT * FROM table2";
myReader = myCommand.ExecuteReader();
while(myReader.Read())
{
//Perform more work
}
myReader.Close();
myConnection.Close();
Thanks a lot.
You can use the same connection for each of them, as long as you do not try to execute multiple queries concurrently on the same connection from different threads.
As for the data reader, you are not actually re-using the reader, each call to ExecuteReader returns a new instance of a new reader, all you are re-using is the variable that maintains the reference to the reader. Here in lies a problem, you are only explicitly closing the last reader and leaving the first to be GC'd at some later time.
You can reuse the Command as well, but remember if you supply parameters etc. you will need to clear them for the next query unless they apply to the next query as well.
You should use try/finally blocks to ensure that you clean up the resources, or here is a quick change to your code to use using statements to ensure resource clean-up even if there is an exception that prevents the rest of the code from executing.
using (var myConnection = GetTheConnection())
{
myConnection.Open();
var myCommand = new MySqlCommand("SELECT * FROM table1", myConnection))
using (var myDataReader = myCommand.ExecuteReader())
{
while(myReader.Read())
{
//Perform work.
}
} // Reader will be Disposed/Closed here
myCommand.commandText = "SELECT * FROM table2";
using (var myReader = myCommand.ExecuteReader())
{
while(myReader.Read())
{
//Perform more work
}
} // Reader will be Disposed/Closed here
} // Connection will be Disposed/Closed here
Note: GetTheConnection is just a place holder function for what ever mechanism you are using to get your connection instance.
I generally use Adapters so I am rusty on the details of the reader, but I think you are on the right track.
One item of note in your code is that each call to ExecuteReader should be generating a new data reader. You may be reusing the variable name, but the reference to the existing reader is discarded and replaced by a new one on each call. Point being, close the previous reader before using ExecuteReader to get a new one.
Related
I have a client/server app and my server stores data in a MySQL database, currently I have made a connection and I do queries without queue or something. I don't think this is a good solution for this, because when a MySQLDataReader opens another one can't be execute at the same time and first one must be closed. I think I have two options, either make a connection by every DataReader or put my queries in a queue to execute them one by one.
I want to know which one is the best or is there any way or something to prevent errors and exception which causes this error
There is already an open DataReader associated with this Connection which must be closed first.
This is how currently I am doing queries. I first get the main connection and do queries. it my causes above error.
string query = "SELECT * FROM users WHERE username = #username";
ServerModel.Database.CheckConnection(); // Get the main connection
MySqlCommand cmd = new MySqlCommand(query, ServerModel.Database);
cmd.Parameters.AddWithValue("#username", username);
UserStatus userStatus;
using (MySqlDataReader dataReader = cmd.ExecuteReader())
{
if (dataReader.Read())
{
...
dataReader.Close();
return userStatus;
}
}
To note that this server may do thousands of queries at moment. think about a chat server.
In this case please don't use the using block, I hope below approach will work fine.
string query = "SELECT * FROM users WHERE username = #username";
ServerModel.Database.CheckConnection(); // Get the main connection
MySqlCommand cmd = new MySqlCommand(query, ServerModel.Database);
cmd.Parameters.AddWithValue("#username", username);
UserStatus userStatus;
MySqlDataReader dataReader = cmd.ExecuteReader()
if (dataReader.Read())
{
...
dataReader.Close();
return userStatus;
}
I am trying to read from datareader but i am gettin the error "Invalid attempt to call Read when reader is closed." The stored procedure is working fine but when i try to read fom datareader it throws error.Plz help me
protected void CheckDatabase()
{
SqlConnection conn = new SqlConnection(GetConnectionString());
conn.Open();
SqlParameter[] param = new SqlParameter[2];
param[0]= new SqlParameter("#EmpID", SqlDbType.Int);
param[0].Value = txtEmpId.Text;
param[1]= new SqlParameter("#Date", SqlDbType.VarChar,50);
param[1].Value = txtDate.Text;
SqlDataReader reader = DNDatabase.ExecuteStoredProcedureReader("RetrieveDeatails", param);
while (reader.Read())
{
gridConfirm.DataSource = reader;
gridConfirm.Columns[0].Visible = false;
gridConfirm.DataBind();
Session["Task_List"] = reader;
}}
here is stored Procedure code
public static SqlDataReader ExecuteStoredProcedureReader(string procedureName, SqlParameter[] parameters)
{
SqlConnection _conn = new SqlConnection(DNDatabase.SQLConnectionString);
SqlCommand cmd = new SqlCommand(procedureName, _conn);
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = procedureName;
cmd.CommandTimeout = 300;
try
{
foreach (SqlParameter param in parameters)
{
cmd.Parameters.Add(param);
}
_conn.Open();
return cmd.ExecuteReader(CommandBehavior.CloseConnection);
}
catch (Exception sqlExc)
{
throw new Exception("An error occured", sqlExc);
}
finally
{
if (_conn != null)
_conn.Close();
}
}
This looks like a bad idea to me:
Session["Task_List"] = reader;
You execute that and then call reader.Read() again, continuing until there's nothing left to read. Presumably you also close the reader at some point (I'd hope - ideally with a using statement). Fundamentally, a SqlDataReader is a connected resource - it's like a stream to the database. It's not something you should be holding onto for longer than you need to, and it's certainly not something you should be putting in a session, even if you didn't effectively invalidate it with the subsequent Read() call.
I assume that data binding works by fetching the data when you call DataBind(), but there's no indication of what you're trying to achieve by putting a reference to the reader itself into the session.
I suggest that:
You isolate whether this is actually to do with the session or the databinding
If it's the session, you pull all of the data you need out (e.g. into a DataTable or some other "disconnected" form)
If it's the databinding, you'll need to do something similar - but as I say, you can hope that that's not the problem, to start with - I assume you saw this sort of databinding elsewhere?
Additionally, you should consider why you want to loop - currently you're basically going to loop over all the results and only the last one is going to be displayed (because you're overwriting the databinding each time). Is that really what you want?
check DNDatabase.ExecuteStoredProcedureReader code may it close the reader after fetchdata
and another thing i should say is:
you can'nt use Session["Task_List"] = reader; because reader is forwardonly
and if you want to keep current value of reader in a seesion load in data table and keep data row of table
DataTable dt = new DataTanle();
dt.Load(dr);
and loop over data table rows
Your method ExecuteStoredProcedureReader has a finally statement which closes the connection. Hence you cannot read anything from the reader. Either close the reader in your method where you call ExecuteStoredProcedureReader or merge both the methods to have them in a single method.
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();
}
I have the code below:
using (SqlCommand command = new SqlCommand())
{
command.CommandType = System.Data.CommandType.StoredProcedure;
command.Connection = new SqlConnection();
command.CommandText = "";
command.Parameters.Add(new SqlParameter("#ExperienceLevel", 3).Direction = System.Data.ParameterDirection.Input);
SqlDataReader dataReader = command.ExecuteReader();
}
Is there any functional impact in declaring the SqlConnection where I currently am declaring it as opposed to like so?:
using (SqlCommand command = new SqlCommand())
using (SqlConnection connection = new SqlConnection())
Thanks
Yes, there's a difference. Disposing the SqlCommand does not automatically dispose the SqlConnection it's associated with. You can leak connections that way, and it will interfere with ADO.NET connection pooling; if you take a look at the database server's activity while this code runs, you'll see new connections being opened and not closed.
You should always be using the second version. In fact, the SqlConnection object is the one that you really need to Dispose. You should always dispose anything that implements IDisposable as soon as possible, but failing to dispose a SqlConnection is particularly dangerous.
Yes, preferably use 2 using blocks, 1 per resource.
In this case you could use just 1 but it should be around the Connection, not around the Command.
But you really don't want to know or care about such details. If a class implements the IDispsoable interface then use its instances in a using() { } block unless there is a special reason not to.
I use the following pattern:
using(var connection = new SqlConnection("ConnectionName"))
using(var command = new SqlCommand())
{
command.Connection = connection;
// setup command
var reader = command.ExecuteReader();
// read from the reader
reader.Close();
}
Yes, the below code will dispose the SqlConnection correctly, the above won't. A using block (implemented internally as try...finally) ensures that the object will be disposed no matter how you exit the block.
I have two questions.
1) Should you always use a using statement on a connection? So, I would use it on the connection and then another one on a reader within the connection? So I would be using two using statements.
2) Lets say you use the using statement on the connection and also a reader being returned on the connection. So you have two using statements. Does it create two Try{}Finally{} blocks or just one?
Thanks!
Be careful here. You should always have a using statement on any local object that implements IDisposable. That includes not only connections and readers, but also the command. But it can be tricky sometimes exactly where that using statement goes. If you're not careful it can cause problems. For example, in the code that follows the using statement will close your reader before you ever get to use it:
DataReader MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
return rdr;
}
}
}
Instead, you have four options. One is to wait to create the using block until you call the function:
DataReader MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
return cmd.ExecuteReader();
}
}
using (var rdr = MyQuery())
{
while (rdr.Read())
{
//...
}
}
Of course, you still have to careful with your connection there and it means remember to write a using block everywhere you use the function.
Option two is just process the query results in the method itself, but that breaks separation of your data layer from the rest of the program. A third option is for your MyQuery() function to accept an argument of type Action that you can call inside the while (rdr.Read()) loop, but that's just awkward.
I generally prefer option four: turn the data reader into an IEnumerable, like this:
IEnumerable<IDataRecord> MyQuery()
{
string sql="some query";
using (var cn = new SqlConnection("connection string"))
using (var cmd = new SqlCommand(sql, cn))
{
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
Now everything will be closed correctly, and the code that handles it is all in one place. You also get a nice bonus: your query results will work well with any of the linq operators.
Finally, something new I'm playing with for the next time I get to build a completely new project that combines the IEnumerable with passing in a delegate argument:
//part of the data layer
private static IEnumerable<IDataRecord> Retrieve(string sql, Action<SqlParameterCollection> addParameters)
{
//DL.ConnectionString is a private static property in the data layer
// depending on the project needs, it can be implementing to read from a config file or elsewhere
using (var cn = new SqlConnection(DL.ConnectionString))
using (var cmd = new SqlCommand(sql, cn))
{
addParameters(cmd.Parameters);
cn.Open();
using (var rdr = cmd.ExecuteReader())
{
while (rdr.Read())
yield return rdr;
}
}
}
And then I'll use it within the data layer like this:
public IEnumerable<IDataRecord> GetFooChildrenByParentID(int ParentID)
{
//I could easily use a stored procedure name instead, and provide overloads for commandtypes.
return Retrieve(
"SELECT c.*
FROM [ParentTable] p
INNER JOIN [ChildTable] c ON c.ParentID = f.ID
WHERE f.ID= #ParentID", p =>
{
p.Add("#ParentID", SqlDbType.Int).Value = ParentID;
}
);
}
1) Should you always use a using
statement on a connection? So, I would
use it on the connection and then
another one on a reader within the
connection? So I would be using two
using statements.
Yes, because they implement IDisposable. And don't forget a using statement on the command too :
using (DbConnection connection = GetConnection())
using (DbCommand command = connection.CreateCommand())
{
command.CommandText = "SELECT FOO, BAR FROM BAZ";
connection.Open();
using (DbDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
....
}
}
}
2) Lets say you use the using
statement on the connection and also a
reader being returned on the
connection. So you have two using
statements. Does it create two
Try{}Finally{} blocks or just one?
Each using statement will create its own try/finally block
You should always use a using statement when an object implements IDisposable. This includes connections.
It will create two nested try{}finally{} blocks.
Special point on 1). You need to specifically avoid that technique when the connection is used in asynchronous ADO.NET methods - like BeginExecuteReader, because more than likely, you will fall out of scope and try to dispose the connection while the async operation is still in progress. This is similar to the case when you are using class variables and not local variables. Often times the connection reference is stored in a class used as the "control block" for the asynchronous operation.
To answer each one:
1) Yes, this would be best practice to dispose both as soon as possible.
2) using() will create two blocks, wrapped in each other in the same order. It will dispose the inner object (the reader) first, then dispose the object from the outer using (the connection).
Probably this article will be interesting for you: How to Implement IDisposable and Finalizers: 3 Easy Rules