I'm working with legacy code here and there are many instances of SqlDataReader that are never closed or disposed. The connection is closed but, I am not sure if it is necessary to manage the reader manually.
Could this cause a slowdown in performance?
Try to avoid using readers like this:
SqlConnection connection = new SqlConnection("connection string");
SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection);
SqlDataReader reader = cmd.ExecuteReader();
connection.Open();
if (reader != null)
{
while (reader.Read())
{
//do something
}
}
reader.Close(); // <- too easy to forget
reader.Dispose(); // <- too easy to forget
connection.Close(); // <- too easy to forget
Instead, wrap them in using statements:
using(SqlConnection connection = new SqlConnection("connection string"))
{
connection.Open();
using(SqlCommand cmd = new SqlCommand("SELECT * FROM SomeTable", connection))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
//do something
}
}
} // reader closed and disposed up here
} // command disposed here
} //connection closed and disposed here
The using statement will ensure correct disposal of the object and freeing of resources.
If you forget then you are leaving the cleaning up to the garbage collector, which could take a while.
Note that disposing a SqlDataReader instantiated using SqlCommand.ExecuteReader() will not close/dispose the underlying connection.
There are two common patterns. In the first, the reader is opened and closed within the scope of the connection:
using(SqlConnection connection = ...)
{
connection.Open();
...
using(SqlCommand command = ...)
{
using(SqlDataReader reader = command.ExecuteReader())
{
... do your stuff ...
} // reader is closed/disposed here
} // command is closed/disposed here
} // connection is closed/disposed here
Sometimes it's convenient to have a data access method open a connection and return a reader. In this case it's important that the returned reader is opened using CommandBehavior.CloseConnection, so that closing/disposing the reader will close the underlying connection. The pattern looks something like this:
public SqlDataReader ExecuteReader(string commandText)
{
SqlConnection connection = new SqlConnection(...);
try
{
connection.Open();
using(SqlCommand command = new SqlCommand(commandText, connection))
{
return command.ExecuteReader(CommandBehavior.CloseConnection);
}
}
catch
{
// Close connection before rethrowing
connection.Close();
throw;
}
}
and the calling code just needs to dispose the reader thus:
using(SqlDataReader reader = ExecuteReader(...))
{
... do your stuff ...
} // reader and connection are closed here.
To be safe, wrap every SqlDataReader object in a using statement.
Just wrap your SQLDataReader with "using" statement. That should take care of most of your issues.
Related
Today I looked through some legacy code and I have began worrying. It is required to close a DataReader explicitly.
My question is: does closing the SqlCommand close the associated DataReader as well?
This is my code:
using (var conn = new SqlConnection(this.ConnectionString))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "House_GetHouseById";
SqlCommandBuilder.DeriveParameters(cmd);
cmd.Parameters["#HouseId"].Value = houseId;
var reader = cmd.ExecuteReader())
while (reader.Read())
{
}
}
}
In this snippet from msdn command is not closed explicitly:
string queryString =
"SELECT OrderID, CustomerID FROM dbo.Orders;";
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlCommand command =
new SqlCommand(queryString, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
// Call Read before accessing data.
while (reader.Read())
{
Console.WriteLine(String.Format("{0}, {1}",
reader[0], reader[1]));
}
// Call Close when done reading.
reader.Close();
}
No. SqlCommand.Dispose is essentially a no-op¹, and it won't close your SqlDataReader.
Technically, closing the SqlConnection should close all resources, see this question for details:
Is closing/disposing an SqlDataReader needed if you are already closing the SqlConnection?
However, this is bad practice -- you are relying on an implementation detail of the SqlClient library. The "correct" way would be to dispose (via Dispose or using) everything that is IDisposable. Thus, your code should be written as follows:
using (var conn = new SqlConnection(this.ConnectionString))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "House_GetHouseById";
SqlCommandBuilder.DeriveParameters(cmd);
cmd.Parameters["#HouseId"].Value = houseId;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
// do something
}
}
}
}
¹ Note that this is not true for the command classes of other libraries such as OleDbCommand and SqlCeCommand, so don't get in the habit of not disposing commands.
You could always wrap the datareader in a using directive so that the command is closed as soon the execution is out of the scope,just like the sqlcommand
using (SqlDataReader reader = cmd.ExecuteReader())
{
if (reader != null)
{
while (reader.Read())
{
//do something
}
}
} // reader is closed here
reader.Close(); //is another way but its too easy to be forgotten.
I call ExecuteReader(); to get data, then i need to get another data with another query. My structure's been always like this :
class SomeClass
{
public static void Main(String[] args)
{
SqlConnection sqlConn = new SqlConnection();
sqlConn.ConnectionString = "some connection string"
SqlCommand SQLCmd = new SqlCommand();
SQLCmd.CommandText = "some query";
SQLCmd.Connection = sqlConn;
sqlConn.Open();
sqlReader = SQLCmd.ExecuteReader();
while (sqlReader.Read())
{
//some stuff here
}
sqlReader.Dispose();
sqlReader.Close();
sqlConn.Close();
SQLCmd.CommandText = "another query";
sqlConn.Open();
sqlReader = SQLCmd.ExecuteReader();
while (sqlReader.Read())
{
//some other stuff here
}
sqlReader.Dispose();
sqlReader.Close();
sqlConn.Close();
}
}
They share the same connection string. What else can they share ? Can they share same sqlConn.Open(); ? What is the proper way of resource allocating and avoiding errors ?
BTW it works as it is. Thanks in advance.
This is how I would write all of that:
class SomeClass
{
public static void Main(String[] args)
{
using (SqlConnection sqlConn = new SqlConnection("some connection string"))
{
sqlConn.Open();
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some other stuff here
}
}
}
}
}
The using statement handles disposing of items when the block is finished. As for sharing stuff, you could leave the connection open across the commands.
The most important thing to dispose out of all of that would be the connection, but I tend towards honouring a using statement if an item is IDisposable regardless of what it actually does in the background (which is liable to change as it's an implementation detail).
Don't forget, there is also Multiple Active Result Sets (as demonstrated in this answer) from a single command and a single reader, where you advance the reader onto the next result set.
My slightly more flippant answer to how I might write all of that would be:
return connection.Query<T>(procedureName, param, commandType: CommandType.StoredProcedure);
Using Dapper ;-)
As alluded to in my comment - if possible, combine the two queries into one and then (if it still produces multiple result sets), use NextResult to move on.
Stealing Adam's structure, but with that change:
class SomeClass
{
public static void Main(String[] args)
{
using (SqlConnection sqlConn = new SqlConnection("some connection string"))
{
sqlConn.Open();
using (SqlCommand comm = new SqlCommand("some query; some other query;", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
if(sqlReader.NextResult())
{
while (sqlReader.Read())
{
//some other stuff here
}
}
}
}
}
}
The proper way is to wrap SqlConnections and SqlCommands in using-statements. This will force Dispose to be invoked on the objects when the using block is left, even if an Exception is thrown. (This is not the case with your current code.)
Something in the line of
using(var cnn = new SqlConnection("connectionstring")){
cnn.Open();
using(var cmd = new SqlCommand("SELECT 1")){
var reader = cmd.ExecuteReader();
while(reader.Read()) { /* doStuff */ }
}
}
Regardless of the approach Close/Dispose will not actually close the connection since connection setup is very expensive. It will just return the connection to a connection pool and allow other commands/readers to use it.
To manage resource you can use using like as shown under
...
SQLCmd.CommandText = "some query";
SQLCmd.Connection = sqlConn;
sqlConn.Open();
//using will dispose reader automatically.
using(sqlReader = SQLCmd.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
//sqlReader.Dispose();
//sqlReader.Close();
//sqlConn.Close();
SQLCmd.CommandText = "another query";
//no need to open connection again.
// sqlConn.Open();
// sqlReader = SQLCmd.ExecuteReader();
using(sqlReader = SQLCmd.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
//sqlReader.Dispose();
//sqlReader.Close();
//sqlConn.Close();
you can use using only for those classes which have implemented IDispose interface.
in your example you can use SqlConnection and SqlCommand also with using code block.
Use 'using', you don't need to manually close and dispose.
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlCommand command = new SqlCommand("spTest", connection);
command.CommandType = CommandType.StoredProcedure;
command.Parameters.Add(new SqlParameter("#employeeid", employeeID));
command.CommandTimeout = 5;
command.ExecuteNonQuery();
}
Open a new connection every time you need it is a best practices. ADO.net use connection pool to menage connection.
http://msdn.microsoft.com/it-it/library/8xx3tyca(v=vs.110).aspx
Dont forget your try catch statements though :)
class SomeClass
{
public static void Main(String[] args)
{
using (SqlConnection sqlConn = new SqlConnection("some connection string"))
{
try{
sqlConn.Open();
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some stuff here
}
}
using (SqlCommand comm = new SqlCommand("some query", conn))
using (var sqlReader = comm.ExecuteReader())
{
while (sqlReader.Read())
{
//some other stuff here
}
}
}
catch()
{
// Do exception catching here or rollbacktransaction if your using begin transact
}
finally
{
sqlConn.Close();
}
}
}
}
Say I do something like this
using (SqlDataReader allUsersDataSource = AdminDB.GetUsers())
{
// bind all portal users to dropdownlist
allUsers.DataSource = allUsersDataSource;
allUsers.DataBind();
}
Will the dataBinded still behave correctly or does it need the SqlDataReader to be undisposed?
EDIT: Additional Information
public static SqlDataReader GetUsers()
{
// Create Instance of Connection and Command Object
using (SqlConnection myConnection = new SqlConnection( (string) PortalSettings.GetPortalSetting("ConnectionString")))
using (SqlCommand myCommand = new SqlCommand("dbo.GetUsers", myConnection))
{
// Mark the Command as a SPROC
myCommand.CommandType = CommandType.StoredProcedure;
// Open the database connection and execute the command
myConnection.Open();
SqlDataReader dr = myCommand.ExecuteReader();
// Return the datareader
return dr;
}
}
The code you are using to bind the data uses using block
using (SqlDataReader allUsersDataSource = AdminDB.GetUsers())
{
// bind all portal users to dropdownlist
allUsers.DataSource = allUsersDataSource;
allUsers.DataBind();
}
using takes only IDisposable objects and calls the Dispose method when the block execution ends. So you need not to worry about Disposing the Reader object here.
I have a function that returns an OracleDataReader object. Here it is :
public OracleDataReader executeCommand(string query)
{
using (conn)
{
conn.ConnectionString = connectionString;
conn.Open();
OracleCommand cmd = conn.CreateCommand();
cmd.CommandText = query;
OracleDataReader reader = cmd.ExecuteReader();
return reader;
}
}
When I tried to to get data with reader in another class i get an exception:
public Person GetPersonById(int id)
{
OracleDBOp db = new OracleDBOp();
String query = "select * from test_person where id=" + id;
OracleDataReader reader = db.executeCommand(query);
Person person = null;
person = new Person(Convert.ToInt32(reader["id"]),reader["first_name"].ToString(),reader["last_name"].ToString());
return person;
}
Exception
Invalid attempt to GetOrdinal when reader is closed.
What is the problem? I am not closing the reader?
Your code closes the connection as soon as the using scope is exited, so any attempts to read will fail:
using (conn)
{
conn.ConnectionString = connectionString;
conn.Open();
...
return reader;
} --> Disposes of connection, which closes it, so reader can't read.
One option is to instead of placing the connection in the using block, if you intend passing the reader outside the control of the method which owns the connection, you can specify CommandBehavior.CloseConnection to close the connection when the reader is closed, but do NOT close or dispose of the connection i.e.
OracleDataReader reader = cmd.ExecuteReader(CommandBehavior.CloseConnection);
return reader;
IMO, a safer pattern (provided that you play nicely with the iterator, e.g. with foreach), without leaving the responsibility of the disposal of resources to the caller, and without passing the reader outside of a function, would be to use yield return, although this will change the way your code works:
public IEnumerable<Person> RetrievePeople()
{
using (var conn = new OracleConnection(connString))
{
conn.Open();
using (var cmd = conn.CreateCommand())
{
cmd.CommandText = query;
using (var reader = cmd.ExecuteReader())
{
while (reader.Read())
{
yield return new new Person(
Convert.ToInt32(reader["id"]),
reader["first_name"].ToString(),
reader["last_name"].ToString());
}
}
}
}
}
This way you don't need to pass the reader around, yet, the connection will be remain open until the iterator completes. This has the benefit of retaining the lazy evaluation approach of the reader, without actually passing the reader around, and without the issue of who is going to clean up the connections afterwards.
I need to run several queries inside one function, will I have to create a new SqlConnection for each? Or having one connection but different SqlCommands works too?
Thanks,
EDIT: Will this work?
using (SqlConnection conn = new SqlConnection(connectionString))
{
conn.Open();
using (SqlCommand cmd = new SqlCommand(query1, conn))
{
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd = new SqlCommand(query2, conn))
{
cmd.ExecuteNonQuery();
}
using (SqlCommand cmd = new SqlCommand(query3, conn))
{
cmd.ExecuteNonQuery();
}
}
Using the MDSN Documentation as a base:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
string sql1 = "SELECT ID,FirstName,LastName FROM VP_PERSON";
string sql2 = "SELECT Address,City,State,Code FROM VP_ADDRESS";
using (SqlCommand command = new SqlCommand(sql1,connection))
{
//Command 1
using (SqlDataReader reader = command.ExecuteReader())
{
// reader.Read iteration etc
}
} // command is disposed.
using (SqlCommand command = new SqlCommand(sql2,connection))
{
//Command 1
using (SqlDataReader reader = command.ExecuteReader())
{
// reader.Read iteration etc
}
} // command is disposed.
// If you don't using using on your SqlCommands you need to dispose of them
// by calling command.Dispose(); on the command after you're done.
} // the SqlConnection will be disposed
It doesn't matter which way you go.
SqlConnections are pooled by the operating system. You could literally open and close a connection thousands of times in a row and not incur any performance or other penalty.
How it works is:
Application makes a request to create a db connection (var c = new SqlConnection(...))
The Operating Systems connection pool looks to see if it has a connection sitting idle. If it does, you get a reference to that. If not then it spins up a new one.
Application indicates it is finished with the connection (c.Dispose())
Operating System keeps the connection open for a certain amount of time in case your app, or another one, tries to create another connection to that same resource.
If that connection stays idle until a timeout period passes then the OS finally closes and releases.
This is why the first time you make a connection to a database it might take a second to start before the command(s) can be processed. However if you close it and reopen it then the connection is available immediately. More information is here: http://msdn.microsoft.com/en-us/library/8xx3tyca(v=vs.110).aspx
Now, as to your code, generally speaking you open 1 SqlConnection each time you make a SqlCommand call; however, it is perfectly acceptable/reasonable to make multiple SqlCommand calls while within the same block under the SqlConnection using clause.
Just bear in mind that you do NOT want to keep a SqlConnection object hanging around in your code for any longer than is absolutely necessary. This can lead to a lot of potential issues, especially if you are doing web development. Which means it's far better for your code to open and close 100 SqlConnection objects in rapid succession than it is to hold onto that object and pass it around through various methods.
Having one SqlConnection and many SqlCommands will work fine, however you must make sure that you dispose of any SqlDataReaders that are returned from previous commands before attempting to run additional commands.
using (SqlConnection conn = new SqlConnection())
{
conn.Open()
using (SqlCommand cmd = new SqlCommand("SELECT myrow FROM mytable", conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Handle first resultset here
}
}
using (SqlCommand cmd = new SqlCommand("SELECT otherrow FROM othertable", conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Handle second resultset here
}
}
}
Alternaitvely you might be able to combine your commands up into one batch and instead process multiple resultsets, like this:
using (SqlConnection conn = new SqlConnection())
{
conn.Open()
using (SqlCommand cmd = new SqlCommand("SELECT myrow FROM mytable; SELECT otherrow FROM othertable", conn))
{
using (SqlDataReader reader = cmd.ExecuteReader())
{
// Handle first resultset here, and then when done call
if (reader.NextResult())
{
// Handle second resultset here
}
}
}
}
When you are processing many resultsets you will find that batching together queries like this can significantly improve performance, however it comes at the price of added complexity in your calling code.
Open only one SQLConnection
Use the keyworkd Using as it will automatically dispose the connection.
If you open connection for each one , it can have performance problems.
Example:
using (SqlConnection con = new SqlConnection(connectionString))
{
//
// Open the SqlConnection.
//
con.Open();
//
// The following code shows how you can use an SqlCommand based on the SqlConnection.
//
using (SqlCommand command = new SqlCommand("SELECT TOP 2 * FROM Dogs1", con))
using (SqlDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.WriteLine("{0} {1} {2}",
reader.GetInt32(0), reader.GetString(1), reader.GetString(2));
}
}
}
One more example:
public DataTable GetData()
{
DataTable dt = new DataTable();
using (SqlConnection con = new SqlConnection("your connection here")
{
con.Open();
using (SqlCommand cmd = con.CreateCommand())
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "your stored procedure here";
using (SqlDataAdapter da = new SqlDataAdapter(cmd))
{
da.Fill(dt);
}
}
}
return dt;
}
Purely as an alternative to the using statements:
SqlConnection con = new SqlConnection(myConnectionString);
SqlCommand cmd = con.CreateCommand();
cmd.CommandText = #"SELECT [stuff] FROM [tableOfStuff]";
con.Open();
SqlDataReader dr = null;
try
{
dr = cmd.ExecuteReader();
while(dr.Read())
{
// Populate your business objects/data tables/whatever
}
}
catch(SomeTypeOfException ex){ /* handle exception */ }
// Manually call Dispose()...
if(con != null) con.Dispose();
if(cmd != null) cmd.Dispose();
if(dr != null) dr.Dispose();
The major difference between this and the using statements, is this will allow you to handle exceptions more cleanly.